You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@openjpa.apache.org by "cristof (via GitHub)" <gi...@apache.org> on 2026/05/16 18:41:04 UTC
[PR] Implements Jakarta Persistence 3.2 [openjpa]
cristof opened a new pull request, #144:
URL: https://github.com/apache/openjpa/pull/144
Hi! This work is an effort to implement JPA 3.2. I've started it a long time ago. Richard Zowalla picked it up and, with AI help (Claude), implemented the missing features, including some JPA <3.0 that weren't implemented.
I've tested it against default database, h2, mariadb(lts) e postgresql (18).
Please, check it against your favorite DB so we may fix some edge cases. It would be great if you can run TCK to be sure of the implementations.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3357208407
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java:
##########
@@ -787,7 +809,7 @@ boolean syncWithManagedTransaction(BrokerImpl broker, boolean begin) {
public Collection<Broker> getOpenBrokers() {
return Collections.unmodifiableCollection(_brokers);
}
-
+
Review Comment:
IMO trailing spaces need to be removed :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4483461236
Hello @rzo1,
I've checked docker compose files, they seems to be very similar to existing dockerized VMs currently stored in pom.xml :)
IMO maven versions are better due to it is possible to change DB version in command line:
`mvn -N -Ptest-postgresql-docker -Dpostgresql.server.version=16.4 docker:start`
:)
All: I was able to fix my `postgres` issues, the build is green at `postgres 11` (not sure why it is broken :( maybe due to postgres driver update ...)
I'll continue my testing and will report back
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3427091440
##########
.github/workflows/ci.yml:
##########
@@ -21,19 +21,19 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- name: Setup Java JDK
- uses: actions/setup-java@v4
+ uses: actions/setup-java@v5
with:
- distribution: 'zulu'
- java-version: 11
+ distribution: 'temurin'
Review Comment:
I'll revert back to `zulu` and we will see build status :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "ilgrosso (via GitHub)" <gi...@apache.org>.
ilgrosso commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4726847725
> @ilgrosso for whatever reason this `KubernetesTCPRemoteCommitProviderTest.addresses:165 expected:<2> but was:<0>` test is unstable ...
@solomax I took a quick look but could not figure out how that test might be unstable; actually, I was able to track down a single failure by looking at GitHub workflow runs.
Since it is a mocked test, I can only suppose that there could be some dependency upgrade in this PR which is interfering somehow.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3584780114
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
Everything works as expected! Thanks a million!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3584129038
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
Thanks for the help @rzo1 :))
I'll try your fixes today/tomorrow :)
`extract(WEEK)` should be fixed with https://github.com/apache/openjpa/pull/144/commits/56c5674637de8ed6b65a492eefe09fa95cd3942c :))
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3505435750
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
@solomax, I'll have a look at that on the weekend. I guess we can tune the OracleDictionary to use the corresponding alternatives.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3771754428
##########
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,
Review Comment:
Removed.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3771760369
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java:
##########
@@ -1341,6 +1376,90 @@ private void parseMemberAnnotations(FieldMetaData fmd) {
}
}
+ /**
Review Comment:
Removed duplicate
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5353859390
Merging, as requested. Sure will help with the issues!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4999209347
I've added validator and now got following Exception:
```
SEVERE: Received unexpected Exception
<openjpa-4.2.0-SNAPSHOT-ra80a08eM nonfatal user error> org.apache.openjpa.persistence.ArgumentException: This configuration disallows runtime optimization, but the following listed types were not enhanced at build time or at class load time with a javaagent: "
ee.jakarta.tck.persistence.se.entityManagerFactory.Order
ee.jakarta.tck.persistence.se.entityManagerFactory.Member".
at org.apache.openjpa.enhance.ManagedClassSubclasser.prepareUnenhancedClasses(ManagedClassSubclasser.java:120)
at org.apache.openjpa.kernel.AbstractBrokerFactory.loadPersistentTypes(AbstractBrokerFactory.java:313)
at org.apache.openjpa.kernel.AbstractBrokerFactory.initializeBroker(AbstractBrokerFactory.java:239)
at org.apache.openjpa.kernel.AbstractBrokerFactory.newBroker(AbstractBrokerFactory.java:215)
at org.apache.openjpa.kernel.DelegatingBrokerFactory.newBroker(DelegatingBrokerFactory.java:168)
at org.apache.openjpa.persistence.EntityManagerFactoryImpl.doCreateEM(EntityManagerFactoryImpl.java:312)
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5003740877
Kubernetes flukes aside, Oracle build is now green, skipping only tests where there is no database support (TIME data type, CURRENT_TIME and EXTRACT(QUARTER from)). Ran the tests on oracle-xe-18 and oracle-xe-21.
Provided the TCK tests are ok, I think we could update the docs and (pre?) release?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4999272245
I'm using: `reset && ./run-tck32.sh` :)
It starts `Postgres:16` and runs everything
As I understand for some reason `jpa.provider.implementation.specific.properties` is not working
I'll try to debug :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3600866618
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/BatchingPreparedStatementManagerImpl.java:
##########
@@ -254,13 +254,22 @@ private void flushSingleRow(RowImpl row, PreparedStatement ps)
row.flush(ps, _dict, _store);
int count = executeUpdate(ps, row.getSQL(_dict), row);
if (count != 1) {
- logSQLWarnings(ps);
- Object failed = row.getFailedObject();
- if (failed != null)
- _exceptions.add(new OptimisticException(failed));
- else if (row.getAction() == Row.ACTION_INSERT)
- throw new SQLException(_loc.get("update-failed-no-failed-obj",
- String.valueOf(count), row.getSQL(_dict)).getMessage());
+ // For DELETE actions, tolerate count=0 because the row may
+ // have already been removed by a database-level ON DELETE
+ // CASCADE triggered by a related row's deletion.
+ if (count == 0 && row.getAction() == Row.ACTION_DELETE) {
Review Comment:
@rmannibucau ping :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801341490
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MySQLDictionary.java:
##########
@@ -536,5 +559,55 @@ public void indexOf(SQLBuffer buf, FilterValue str, FilterValue find,
}
buf.append(")");
}
+
+ /**
+ * MySQL / MariaDB do not support ANSI SQL {@code NULLS FIRST} / {@code NULLS LAST}.
+ * Emulate via an auxiliary {@code <expr> IS NULL} sort key.
+ * <p>
+ * MySQL's default NULL ordering places NULLs before non-NULLs when sorting
+ * ASC and after non-NULLs when sorting DESC. When the requested precedence
+ * already matches that default, nothing extra is emitted. Otherwise the
+ * last order term {@code <expr> ASC|DESC} is rewritten to
+ * {@code <expr> IS NULL <sort>, <expr> ASC|DESC}.
+ */
+ @Override
+ public void appendNullsPrecedence(SQLBuffer ordering, int nullPrecedence) {
+ if (nullPrecedence != QueryExpressions.NULLS_FIRST
+ && nullPrecedence != QueryExpressions.NULLS_LAST) {
+ return;
+ }
+ String sql = ordering.getSQL();
+ int lastAsc = sql.lastIndexOf(" ASC");
+ int lastDesc = sql.lastIndexOf(" DESC");
+ boolean asc;
+ int termDirStart;
+ int termDirEnd;
+ if (lastAsc > lastDesc) {
+ asc = true;
+ termDirStart = lastAsc;
+ termDirEnd = lastAsc + " ASC".length();
+ } else if (lastDesc >= 0) {
+ asc = false;
+ termDirStart = lastDesc;
+ termDirEnd = lastDesc + " DESC".length();
+ } else {
+ return;
+ }
+ boolean defaultMatches =
+ (nullPrecedence == QueryExpressions.NULLS_FIRST && asc)
+ || (nullPrecedence == QueryExpressions.NULLS_LAST && !asc);
+ if (defaultMatches) {
+ return;
+ }
+ int termStart = Math.max(sql.lastIndexOf(", ", termDirStart), -1);
Review Comment:
please see 52f4c065d for generalization and basic test
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801431795
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java:
##########
@@ -477,7 +823,160 @@ public boolean isLoaded(Object entity, String attribute) {
return (OpenJPAPersistenceUtil.isManagedBy(this, entity) &&
(OpenJPAPersistenceUtil.isLoaded(entity, attribute) == LoadState.LOADED));
}
-
+
+ @Override
+ public <E> boolean isLoaded(E entity, Attribute<? super E, ?> attribute) {
+ return isLoaded(entity, attribute.getName());
+ }
+
+ @Override
+ public SchemaManager getSchemaManager() {
+ if (!this.isOpen()) {
+ throw new IllegalStateException("EntityManagerFactory is closed.");
+ }
+ return new SchemaManagerImpl(_factory);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <R> R callInTransaction(Function<EntityManager, R> work) {
+ EntityManager em = createEntityManager();
+ boolean startedTransaction = false;
+ boolean jtaTransaction = getTransactionType() == PersistenceUnitTransactionType.JTA;
+ Broker broker = em.unwrap(Broker.class);
+ try {
+ if (jtaTransaction) {
+ if (!broker.syncWithManagedTransaction()) {
+ broker.begin();
+ startedTransaction = true;
+ }
+ } else {
+ em.getTransaction().begin();
+ startedTransaction = true;
+ }
+ R result = work.apply(em);
+ if (startedTransaction) {
+ if (jtaTransaction) {
+ broker.commit();
+ } else {
+ em.getTransaction().commit();
+ }
+ }
+ // For unenhanced (runtime-subclassed) entities, the user's function
+ // may return an original POJO that was passed to persist().
+ // Entities loaded via find() on other EMs are subclass instances,
+ // causing getClass() mismatches in equals(). To ensure consistent
+ // class identity, re-find managed entities from the database so that
+ // the returned instance is a subclass (matching what find() returns).
+ if (result != null && em.contains(result)) {
+ try {
+ Object id = getPersistenceUnitUtil().getIdentifier(result);
+ if (id != null) {
+ Class<R> entityClass = (Class<R>) result.getClass();
+ em.clear();
+ R refound = em.find(entityClass, id);
+ if (refound != null) {
+ result = refound;
+ }
+ }
+ } catch (Exception e) {
+ // If re-find fails, return original result
+ }
+ }
+ return result;
+ } catch (Exception ex) {
+ if (jtaTransaction) {
+ broker.rollback();
+ } else {
+ try {
+ em.getTransaction().rollback();
+ } catch (Exception rollbackEx) {
+ // Transaction may already be rolled back
+ }
+ }
+ throw new UserException(ex.getMessage(), ex);
+ } finally {
+ em.close();
+ }
+ }
+
+ @Override
+ public void runInTransaction(Consumer<EntityManager> work) {
+ callInTransaction(em -> {
+ work.accept(em);
+ return null;
+ });
+ }
+
+ @Override
+ public <T> Class<? extends T> getClass(T entity) {
+ if (!OpenJPAPersistenceUtil.isManagedBy(this, entity)) {
+ throw new jakarta.persistence.PersistenceException(_loc.get("invalid_entity_argument",
+ "getClass", entity == null ? "null" : Exceptions.toString(entity)).getMessage());
+ }
+ return OpenJPAPersistenceUtil.getClass(this, entity);
+ }
+
+ @Override
+ public <R> Map<String, TypedQueryReference<R>> getNamedQueries(Class<R> resultType) {
+ throw new UnsupportedOperationException("Not yet implemented (JPA 3.2)");
+ }
+
+ @Override
+ public PersistenceUnitTransactionType getTransactionType() {
+ return "managed".equalsIgnoreCase(_factory.getConfiguration().getTransactionMode())
+ ? PersistenceUnitTransactionType.JTA
+ : PersistenceUnitTransactionType.RESOURCE_LOCAL;
+ }
+
+ @Override
+ public Object getVersion(Object entity) {
+ if (!OpenJPAPersistenceUtil.isManagedBy(this, entity)) {
+ throw new IllegalArgumentException(_loc.get("invalid_entity_argument",
Review Comment:
fixed
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4999061550
I've added test to easily reproduce `A default ValidatorFactory could not be created.` issue
I believe we need to create OpenJPA impl for `ValidationProvider` and specify it in `META-INF/services/jakarta.validation.spi.ValidationProvider`
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3687188286
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Left.java:
##########
@@ -0,0 +1,68 @@
+/*
+ * 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.kernel.exps;
+
+import org.apache.openjpa.kernel.StoreContext;
+
+/**
+ * Take the left part of a string.
+ *
+ * @author Abe White
+ * @author Paulo Cristovão Filho
+ */
+class Left
+ extends Val {
+
+
+ private static final long serialVersionUID = 1L;
+ private final Val _val;
+ private final Val _len;
+
+ /**
+ * Constructor. Provide substring and length of the left part that must be kept.
+ */
+ public Left(Val val, Val len) {
+ _val = val;
+ _len = len;
+ }
+
+ @Override
+ public Class getType() {
+ return String.class;
+ }
+
+ @Override
+ public void setImplicitType(Class type) {
+ }
+
+ @Override
+ protected Object eval(Object candidate, Object orig, StoreContext ctx, Object[] params) {
+ Object str = _val.eval(candidate, orig, ctx, params);
+ Object arg = _len.eval(candidate, orig, ctx, params);
+ return str.toString().substring(0, ((Number) arg).intValue());
Review Comment:
Fixed both Left and Right in-memory, mimicking postgresql behavior when using negative number.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801441707
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/common/apps/CompUser.java:
##########
@@ -66,6 +67,9 @@ public class CompUser {
@Enumerated
@Basic
private CreditRating creditRating;
+
+ @Version
Review Comment:
Thanks a million! :))
Please don't forget to file JIRA (too much of them are currently not being processed :(( )
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801752046
##########
openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java:
##########
@@ -2365,10 +2419,20 @@ public boolean is_systemListenersActivated() {
* Add the given system lifecycle listener.
*/
public void addSystemListener(Object listener) {
+ addSystemListener(listener, null);
+ }
+
+ /**
+ * Add a system lifecycle listener with an optional deduplication key.
+ * If a key is provided and a listener with the same key was already
+ * registered, the duplicate is silently skipped.
+ */
+ public void addSystemListener(Object listener, String key) {
+ if (key != null && !_systemListenerKeys.add(key)) {
Review Comment:
Should be fixed with e44b47047
@rzo1 please take a look at the fix (this seems to be your code ;)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801780390
##########
openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java:
##########
@@ -2365,10 +2419,20 @@ public boolean is_systemListenersActivated() {
* Add the given system lifecycle listener.
*/
public void addSystemListener(Object listener) {
+ addSystemListener(listener, null);
+ }
+
+ /**
+ * Add a system lifecycle listener with an optional deduplication key.
+ * If a key is provided and a listener with the same key was already
+ * registered, the duplicate is silently skipped.
+ */
+ public void addSystemListener(Object listener, String key) {
+ if (key != null && !_systemListenerKeys.add(key)) {
Review Comment:
Looks ok to me.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3781862152
##########
scripts/run-build-matrix.sh:
##########
@@ -0,0 +1,222 @@
+#!/bin/bash
Review Comment:
license header is added
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5030756650
> Kubernetes flukes aside, Oracle build is now green, skipping only tests where there is no database support (TIME data type, CURRENT_TIME and EXTRACT(QUARTER from)). Ran the tests on oracle-xe-18 and oracle-xe-21. Provided the TCK tests are ok, I think we could update the docs and (pre?) release?
OpenJPA historically never passed the full TCK - so we can either try to get it green (again) for certain rdbms or we make a (pre?) release with updated docs and do the TCK work in another follow up PR? wdyt?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3781699082
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestJava8TimeTypes.java:
##########
@@ -255,12 +265,70 @@ public void testGetCurrentLocalDateTime() {
}
public void testGetCurrentLocalTime() {
+ DBDictionary dict = getDbDictionary(emf);
+ if (dict instanceof OracleDictionary) {
+ // Oracle has no TIME data type
+ return;
+ }
+
EntityManager em = emf.createEntityManager();
- final TypedQuery<Java8TimeTypes> qry
- = em.createQuery("select j from Java8TimeTypes AS j where j.localTimeField < LOCAL TIME", Java8TimeTypes.class);
+ final TypedQuery<Java8TimeTypes> qry = em.createQuery(
+ "select j from Java8TimeTypes AS j where j.localTimeField < LOCAL TIME OR j.localTimeField >= LOCAL TIME", Java8TimeTypes.class);
Review Comment:
Hello @rmannibucau,
due to nature of local time it is hard to write condition which will pass :((
the test occasionally fails all the time
I can try to set something like `00:00` and hope test execution will not happen on midnight
Would it be better?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3781884372
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
</bind>
</volumes>
<ports>
<port>${docker.external.oracle.port}:1521</port>
+ <port>5500:5500</port>
</ports>
+ <wait>
+ <log>DATABASE IS READY TO USE</log>
+ <time>3600000</time>
+ </wait>
</run>
</image>
</images>
</configuration>
+ <dependencies>
Review Comment:
I'm getting
```
Exception in thread "Thread-2" java.lang.NoClassDefFoundError: com/google/common/io/ByteStreams$LimitedInputStream
at io.fabric8.maven.docker.access.log.LogRequestor.readFully(LogRequestor.java:128)
at io.fabric8.maven.docker.access.log.LogRequestor.readStreamFrame(LogRequestor.java:144)
at io.fabric8.maven.docker.access.log.LogRequestor.parseResponse(LogRequestor.java:187)
at io.fabric8.maven.docker.access.log.LogRequestor.run(LogRequestor.java:104)
Caused by: java.lang.ClassNotFoundException: com.google.common.io.ByteStreams$LimitedInputStream
at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:42)
at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass(ClassRealm.java:211)
at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:202)
at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:198)
... 4 more
```
And tried to fix it
Will drop
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3812614388
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypesafeCriteria.java:
##########
@@ -1781,5 +1789,168 @@ public void testIdClass() {
assertEquivalence(cq, jpql);
}
+
+ public void testLeft() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where left(p.name, 4) = 'John'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.left(c.get("name"), 4), "John"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testRight() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where RIGHT(p.name, 3) = 'Doe'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.right(c.get("name"), 3), "Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testReplace() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ String jpql = "select p from Person p where REPLACE(p.name, 'ohn', 'ack') = 'Jack Fitzgerald Doe'";
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.replace(c.get("name"), "ohn", "ack"), "Jack Fitzgerald Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ /**
+ * JPA 3.2 Criteria UNION must execute end-to-end and produce the
+ * same SQL as the JPQL UNION form. We don't compare row counts
+ * because TestTypesafeCriteria shares a static EMF with other test
+ * classes and we don't want to seed shared tables.
+ */
+ public void testCriteriaUnion() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 30));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.equal(r2.get("name"), "Ugo"));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> union = cb.union(q1, q2);
+ assertNotNull(em.createQuery(union).getResultList());
+ }
+
+ public void testCriteriaUnionAll() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 25));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.gt(r2.<Integer>get("age"), 30));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> unionAll = cb.unionAll(q1, q2);
+ assertNotNull(em.createQuery(unionAll).getResultList());
+ }
+
+ public void testCriteriaExcept() {
Review Comment:
Looks good, @solomax. That's how we're dealing with the idiosyncrasies of different databases dialects.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3548785944
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
Hello @cristof,
my Oracle tests were against `18.4.0-xe` as the oldest ones. And it seems to stuck :((
I've restarted everything:
- fixed `TestJDBCSchemaManager` one more time (Postgres has specific keyword for `BLOB` ...)
- Find out `test-hsqldb` is now broken :(
I'll re-run everything one more time
Can you please take a look at `test-hsqldb` errors? they seems to be connected with newly added operations ...
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4987870333
Not sure if this need to be addressed in this PR (or in this release)
But our build is RED if `Java-21` is used (all `proxy` related tests fails)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4990919050
great it is fixed in this branch :)
Thanks for updating the CI build!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3437879199
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java:
##########
@@ -467,8 +467,16 @@ private void setInverseRelation(OpenJPAStateManager owner,
continue;
}
OpenJPAStateManager sm = (OpenJPAStateManager) pc.pcGetStateManager();
- ClassMapping cm =
- (ClassMapping) _conf.getMetaDataRepositoryInstance().getCachedMetaData(pc.getClass());
+ if (sm == null) {
Review Comment:
I would already have thrown ClassCastException at the (PersistenceCapable) o cast on line 465 if there is broken enhancement, no?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5353469513
Hello All,
I have created https://issues.apache.org/jira/browse/OPENJPA-2945 and all remaining issues as it's subtasks
@cristof please merge this one :) this honor is yours :)
I hope to get your and @rzo1 help on resolving remaining issues :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3584817036
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
I think we can do that ;)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3588337324
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
Thanks for the report — I could reproduce this and tracked it down.
I debugged it with a small standalone `main()` against a fresh in-memory HSQLDB (`jdbc:hsqldb:mem:x`), just dumping `DatabaseMetaData.getTables` / `getColumns` output. On a completely empty database:
```
getTables(null, null, "TRANSLATIONS", null)
-> CAT=PUBLIC SCHEM=INFORMATION_SCHEMA NAME=TRANSLATIONS TYPE=SYSTEM TABLE
getColumns(null, null, "TRANSLATIONS", null)
-> 12 rows, all TABLE_SCHEM=INFORMATION_SCHEMA
getColumns(null, "PUBLIC", "TRANSLATIONS", null)
-> (no rows)
```
So the SQL standard defines an information-schema view named `TRANSLATIONS`, and HSQLDB implements it. Since the test entity maps to `@Table(name="TRANSLATIONS")` without a schema, OpenJPA's schema reflection calls `getColumns` with a null schema pattern, gets back the columns of `INFORMATION_SCHEMA.TRANSLATIONS`, and concludes the table already exists but is missing the entity columns — hence the `ALTER TABLE TRANSLATIONS ADD COLUMN id BIGINT` against `PUBLIC`, where no such table exists.
The generic code already has a filter for exactly this (`DBDictionary.isSystemTable` / `systemSchemaSet`, consulted in `SchemaGenerator.generateTables`), and the Oracle/Postgres dictionaries use it — the HSQL dictionary just never registers its system schemas. Maybe something like this works (in the `HSQLDictionary` constructor):
```java
// HSQLDB reports the tables and views of its system schemas (e.g.
// INFORMATION_SCHEMA.TRANSLATIONS) via DatabaseMetaData when no
// schema is specified; filter them out so they are not mistaken
// for user tables during schema reflection (OPENJPA-2940).
systemSchemaSet.addAll(Arrays.asList(
"INFORMATION_SCHEMA", "SYSTEM_LOBS"
));
```
With that change, `TestTablePerClassInheritanceWithAbstractRoot` (the test owning the `TRANSLATIONS` entity) passes on `-Ptest-hsqldb`, and the sequence/generator tests still pass. I also checked the rest of the test suite for other collisions with HSQLDB's information-schema names — `TRANSLATIONS` is the only one.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3588437336
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
I debugged the time stuff also with a small standalone `main()` against an in-memory HSQLDB (`jdbc:hsqldb:mem:x`), creating the column once as `TIME WITH TIME ZONE` (what OpenJPA currently generates for `java.time.OffsetTime` on HSQLDB) and once as plain `TIME`, and inserting the values exactly the way our `DBDictionary` binds them.
The key point is how OpenJPA handles `OffsetTime` in `DBDictionary`: on store, the value is normalized to the JVM default offset and bound as a plain `java.sql.Time` (`val.withOffsetSameInstant(OffsetDateTime.now().getOffset()).toLocalTime()`); on load, a plain `Time` is read and the JVM default offset is re-attached. So the offset that ends up in the database is always the session offset - it carries no real information - and the normalization can wrap the local time past midnight. In your run: `04:57:15-09:00` became `20:57:15+07:00`, but the second value (persisted from `LocalTime.now()` at offset `-09:00`) wrapped to `05:12:34+07:00`.
HSQLDB then does the standard-compliant thing for `TIME WITH TIME ZONE` and computes `MAX`/`MIN` by the UTC instant: `05:12:34+07:00` is `22:12:34Z` while `20:57:15+07:00` is only `13:57:15Z`, so `MAX` returns `05:12:34+07:00` - exactly the "wrong" value from the assertion, and `MIN` returns the mirror image, which is why both are broken at once. My standalone program shows both variations: with a `TIME WITH TIME ZONE` column I get your failure, with a plain `TIME` column I get the expected values. It also explains why the failure depends on the time of day / timezone the test runs in: it only bites when one of the persisted values wraps past midnight during the normalization.
Every other dictionary avoids this by storing a zone-less type for `OffsetTime` (Derby maps `TIME_WITH_TIMEZONE` to `TIME` in `getPreferredType`, SQLServer and older H2 set `timeWithZoneTypeName = "TIME"`), which matches the local-time semantics of our normalize-to-JVM-offset scheme. So I'd do the same for HSQLDB. Maybe something like this works:
```java
// HSQLDictionary
@Override
public int getPreferredType(int type) {
if (type == Types.TIME_WITH_TIMEZONE) {
// HSQLDB compares TIME WITH TIME ZONE values by their UTC instant
// (SQL standard), but OpenJPA normalizes OffsetTime values to the
// JVM default offset on store and load. The stored offset therefore
// carries no information, while the normalization may wrap the local
// time around midnight, so MIN/MAX/ORDER BY on such a column return
// different rows than on other databases. Use a plain TIME column
// instead so comparisons happen on the normalized local time.
return Types.TIME;
}
if (dbMajorVersion > 1) {
return super.getPreferredType(type);
}
// ... existing 1.x handling unchanged
}
```
With that change `TestJava8TimeTypes` passes on `-Ptest-hsqldb` (17/17). To be sure it isn't just passing by luck of the clock, I also ran it with `TZ=Etc/GMT-11`, which deterministically triggers the midnight wrap: without the change it fails with exactly your signature (`expected:<21:55:42+11:00> but was:<00:57:15+11:00>` plus the mirrored `testMinOffsetTime` failure), with the change it is green.
For completeness: binding the `OffsetTime` natively via `setObject` instead would not help here — the aggregate would still be computed on UTC instants and disagree with what the test (and all other supported databases) expect. This also covers the `MIN(...)` case from your follow-up comment.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3588437336
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
I debugged this with a small standalone `main()` against an in-memory HSQLDB (`jdbc:hsqldb:mem:x`), creating the column once as `TIME WITH TIME ZONE` (what OpenJPA currently generates for `java.time.OffsetTime` on HSQLDB) and once as plain `TIME`, and inserting the values exactly the way our `DBDictionary` binds them.
The key point is how OpenJPA handles `OffsetTime` in `DBDictionary`: on store, the value is normalized to the JVM default offset and bound as a plain `java.sql.Time` (`val.withOffsetSameInstant(OffsetDateTime.now().getOffset()).toLocalTime()`); on load, a plain `Time` is read and the JVM default offset is re-attached. So the offset that ends up in the database is always the session offset — it carries no real information — and the normalization can wrap the local time past midnight. In your run: `04:57:15-09:00` became `20:57:15+07:00`, but the second value (persisted from `LocalTime.now()` at offset `-09:00`) wrapped to `05:12:34+07:00`.
HSQLDB then does the standard-compliant thing for `TIME WITH TIME ZONE` and computes `MAX`/`MIN` by the UTC instant: `05:12:34+07:00` is `22:12:34Z` while `20:57:15+07:00` is only `13:57:15Z`, so `MAX` returns `05:12:34+07:00` — exactly the "wrong" value from the assertion, and `MIN` returns the mirror image, which is why both are broken at once. My standalone program shows both variations: with a `TIME WITH TIME ZONE` column I get your failure, with a plain `TIME` column I get the expected values. It also explains why the failure depends on the time of day / timezone the test runs in: it only bites when one of the persisted values wraps past midnight during the normalization.
Every other dictionary avoids this by storing a zone-less type for `OffsetTime` (Derby maps `TIME_WITH_TIMEZONE` to `TIME` in `getPreferredType`, SQLServer and older H2 set `timeWithZoneTypeName = "TIME"`), which matches the local-time semantics of our normalize-to-JVM-offset scheme. So I'd do the same for HSQLDB. Maybe something like this works:
```java
// HSQLDictionary
@Override
public int getPreferredType(int type) {
if (type == Types.TIME_WITH_TIMEZONE) {
// HSQLDB compares TIME WITH TIME ZONE values by their UTC instant
// (SQL standard), but OpenJPA normalizes OffsetTime values to the
// JVM default offset on store and load. The stored offset therefore
// carries no information, while the normalization may wrap the local
// time around midnight, so MIN/MAX/ORDER BY on such a column return
// different rows than on other databases. Use a plain TIME column
// instead so comparisons happen on the normalized local time.
return Types.TIME;
}
if (dbMajorVersion > 1) {
return super.getPreferredType(type);
}
// ... existing 1.x handling unchanged
}
```
With that change `TestJava8TimeTypes` passes on `-Ptest-hsqldb` (17/17). To be sure it isn't just passing by luck of the clock, I also ran it with `TZ=Etc/GMT-11`, which deterministically triggers the midnight wrap: without the change it fails with exactly your signature (`expected:<21:55:42+11:00> but was:<00:57:15+11:00>` plus the mirrored `testMinOffsetTime` failure), with the change it is green.
For completeness: binding the `OffsetTime` natively via `setObject` instead would not help here — the aggregate would still be computed on UTC instants and disagree with what the test (and all other supported databases) expect. This also covers the `MIN(...)` case from your follow-up comment.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3563129084
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
I need help on this one as well :( (I'm totally lost in the code :(( )
this simple JPQL is transformed to following SQL: `SELECT ROUND(CAST((CAST(SUM(t0.age) AS NUMERIC) / ?) AS DOUBLE), CAST(? AS DOUBLE)) FROM CompUser t0`
at `hsqldb`
Which leads to
```
Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: incompatible data type in operation in statement [SELECT ROUND(CAST((CAST(SUM(t0.age) AS NUMERIC) / ?) AS DOUBLE), CAST(? AS DOUBLE)) FROM CompUser t0] {SELECT ROUND(CAST((CAST(SUM(t0.age) AS NUMERIC) / ?) AS DOUBLE), CAST(? AS DOUBLE)) FROM CompUser t0} [code=-5563, state=42563]
```
I believe this is because second argument of ROUND should be `INT` (not `DOUBLE`)
how it can be fixed? :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3556524731
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
> @cristof do we have some sort of variable for it? :))
I've added `naturalLogarithmFunction` :) now testing :))
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4999604481
@solomax I looked into the `Client2#createEntityManagerFactoryNoBeanValidatorTest` issue and could reproduce both states on PostgreSQL 16. The test actually **passes** without the bval change: it verifies JPA spec 3.6.1 — `ValidationMode.CALLBACK` with *no* Bean Validation provider on the classpath must end in a `PersistenceException`, and OpenJPA already throws it (`ValidationUnavailableException` → wrapped in `PersistenceProviderImpl`). The `ERROR ... A default ValidatorFactory could not be created` stack trace in the log is expected output on the passing path.
That's also why the TCK runs this single test in the separate `persistence-tests-2` execution: `persistence-tests-1` gets hibernate-validator via `${validator.classes}`, while `persistence-tests-2` deliberately has no validator. Adding `org.apache.bval.bundle` to our profile puts a validator on both classpaths, so the EMF now gets created, `em.persist()` runs, and it fails on the unenhanced `Order`/`Member` classes instead — could you revert 45880938d?
Re `jpa.provider.implementation.specific.properties` "not working": for this one test that's by TCK design — `Client2` passes the raw `myProps` to `createEntityManagerFactory` and never calls `PMClientBase.getPersistenceUnitProperties()`, which is the only place that string gets parsed into `openjpa.*` properties. For all other tests it works fine.
Verified A/B/A on `postgres:16` with a fresh branch-tip build, running only the `persistence-tests-2` execution: without bval → `Tests run: 1, Failures: 0, Errors: 0`; with bval → the `ArgumentException: This configuration disallows runtime optimization` failure you saw; reverted → green again.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4497967367
[status update] I was able to fix one of `mysql 9.4` issues, now investigating others
Will report back as soon later
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3780887688
##########
openjpa-integration/tck/tck32-openjpa-profile.xml:
##########
@@ -0,0 +1,78 @@
+<!--
+ 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.
+-->
+
+<!--
+ This file contains the OpenJPA profile XML fragment to be inserted into
+ the JPA 3.2 TCK runner pom.xml (persistence-tck/bin/pom.xml).
+ It is injected automatically by the tck32-profile build.
+-->
+<profile>
+ <id>openjpa</id>
+ <properties>
+ <glassfish-artifact-id>glassfish</glassfish-artifact-id>
+ <openjpa.version>4.2.0-SNAPSHOT</openjpa.version>
Review Comment:
comment is added
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3781950581
##########
.gitignore:
##########
@@ -11,3 +11,11 @@ nbactions*.xml
.checkstyle
.vscode
+.claude
+CLAUDE.md
+tck-dev
+docker-compose.yml
+pgdata
+openjpa-xmlstore/jdbc*
Review Comment:
one of the folder is created for connection URL: `"jdbc:derby:target/database/openjpa-test-database;create=true"`
I would say the URL states the DB file should be created at `target` folder, but it `just doesn't work` ...
and Derby is retired ...
I would say we should remove Derby or leave this part as-is
WDYT?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5323990530
> Reading from file /home/runner/work/openjpa/openjpa/openjpa-kernel/target/javacc-1785507996706/node/JPQL.jj . . .
> Warning: Choice conflict in (...)* construct at line 1053, column 17.
> Expansion nested within construct and expansion following construct
> have common prefixes, one of which is: "+"
> Consider using a lookahead of 2 or more for nested expansion.
> Warning: Choice conflict in (...)* construct at line 1062, column 17.
> Expansion nested within construct and expansion following construct
> have common prefixes, one of which is: "*"
> Consider using a lookahead of 2 or more for nested expansion.
> Warning: Choice conflict involving two expansions at
> line 1533, column 12 and line 1534, column 12 respectively.
> A common prefix is: "AVG" "("
> Consider using a lookahead of 3 or more for earlier expansion.
> Warning: Choice conflict involving two expansions at
> line 1533, column 34 and line 1534, column 12 respectively.
> A common prefix is: <IDENTIFIER>
> Consider using a lookahead of 2 for earlier expansion.
I let Claude having a adversial review on this one. I would follow its suggestions and move that in a separate Jira to avoid bloating this PR ;-)
This is the output:
Looked into the four JavaCC warnings. Short version: two are a real, ~20-year-old
correctness bug worth a separate JIRA; two are new on this branch but semantically identical.
First, a mapping note: jjtree preserves the original `.jjt` token positions when it writes
`JPQL.jj`, so those line/column numbers are already coordinates in `JPQL.jjt`, not in the
generated file. I reproduced all four verbatim (identical lines *and* columns) with the same
`javacc-5.0.jar` the build uses.
**Warnings 1 & 2 — `"+"` at 1053:17, `"*"` at 1062:17 - real bug, pre-existing.**
`arithmetic_expression()` / `arithmetic_term()` eliminated left recursion by recursing
*right* into themselves, so all binary arithmetic parses right-associative. Precedence is
fine; associativity is not. Confirmed by dumping trees from the real parser:
| expression | tree today |
|---|---|
| `10 - 3 - 2` | `SUBTRACT(10, SUBTRACT(3,2))` = 9, not 5 |
| `x.a / x.b / x.c` | `DIVIDE(a, DIVIDE(b,c))` |
| `x.a - x.b + x.c` | `SUBTRACT(a, ADD(b,c))` |
Nothing downstream repairs it: `DBDictionary.mathFunction` (:3386-3406) wraps every binary
op in its own parens, so the wrong grouping goes into the SQL verbatim. `WHERE x.total -
x.paid - x.refunded > 0` is wrong today.
Pre-existing, not from this branch: the block i and
`git log -S` bottoms out at 1fede626e (2006, original code donation). Only the line numbers
moved (974→1053) because ~79 lines were added a
Fix is to recurse into the next-tighter product
```diff
- ((<PLUS> arithmetic_expression() #ADD(2))
- | (<MINUS> arithmetic_expression(
+ ((<PLUS> arithmetic_term() #ADD(2))
+ | (<MINUS> arithmetic_term() #SUB
(and arithmetic_term → arithmetic_factor likewiarnings drop
4→2, trees become left-leaning, precedence preserved. I parsed a 1564-query corpus harvested
from the test sources under both parsers: 0 acc exactly 2
tree-shape differences, both TestJPQLScalarExpressions.java:121,130
(SUM(c.age) - MIN(c.userid) + MAX(c.userid)), wo won't catch
the change.
Note the LOOKAHEAD(2) that JavaCC suggests is the wrong fix — I verified it produces
byte-identical (still right-associative) trees.ithout fixing
anything.
Since this changes emitted SQL for unparenthesised chained arithmetic, I'd file it as its
own JIRA with a release note and tree-shape regrser currently has
no arithmetic associativity assertion at all.
Warnings 3 & 4 — "AVG" "(" / <IDENTIFIER> at 1533/1534 — new here, but inert.
In orderby_item(), alternatives 4-5 (orderby_extension(), identification_variable())
carry no LOOKAHEAD, so JavaCC resolves by firstuates
LOOKAHEAD(scalar_expression()) on alternative 6 — making that alternative dead for
AVG/MIN/MAX/SUM/COUNT and for bare identifiers.
Introduced jointly: f90549c15 (NULLS FIRST/LASTion() alternative
first, where its lookahead suppressed the warnings; a5d724993 (ORDER BY alias regression)
moved it below the two bare alternatives, which
But the affected queries fail on master too — O is a
ParseException there as well — so this is an unrealised extension, not a regression, and
a5d724993 was a genuine fix that shouldn't be r under-report the
real shape of the gap: ORDER BY a.balance * 2 and ORDER BY -a.balance fail too, silently,
via the lookahead-ful alternatives.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801233626
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MySQLDictionary.java:
##########
@@ -536,5 +559,55 @@ public void indexOf(SQLBuffer buf, FilterValue str, FilterValue find,
}
buf.append(")");
}
+
+ /**
+ * MySQL / MariaDB do not support ANSI SQL {@code NULLS FIRST} / {@code NULLS LAST}.
+ * Emulate via an auxiliary {@code <expr> IS NULL} sort key.
+ * <p>
+ * MySQL's default NULL ordering places NULLs before non-NULLs when sorting
+ * ASC and after non-NULLs when sorting DESC. When the requested precedence
+ * already matches that default, nothing extra is emitted. Otherwise the
+ * last order term {@code <expr> ASC|DESC} is rewritten to
+ * {@code <expr> IS NULL <sort>, <expr> ASC|DESC}.
+ */
+ @Override
+ public void appendNullsPrecedence(SQLBuffer ordering, int nullPrecedence) {
+ if (nullPrecedence != QueryExpressions.NULLS_FIRST
+ && nullPrecedence != QueryExpressions.NULLS_LAST) {
+ return;
+ }
+ String sql = ordering.getSQL();
+ int lastAsc = sql.lastIndexOf(" ASC");
+ int lastDesc = sql.lastIndexOf(" DESC");
+ boolean asc;
+ int termDirStart;
+ int termDirEnd;
+ if (lastAsc > lastDesc) {
+ asc = true;
+ termDirStart = lastAsc;
+ termDirEnd = lastAsc + " ASC".length();
+ } else if (lastDesc >= 0) {
+ asc = false;
+ termDirStart = lastDesc;
+ termDirEnd = lastDesc + " DESC".length();
+ } else {
+ return;
+ }
+ boolean defaultMatches =
+ (nullPrecedence == QueryExpressions.NULLS_FIRST && asc)
+ || (nullPrecedence == QueryExpressions.NULLS_LAST && !asc);
+ if (defaultMatches) {
+ return;
+ }
+ int termStart = Math.max(sql.lastIndexOf(", ", termDirStart), -1);
Review Comment:
Hello @rmannibucau,
I wrote the test with `COALESCE` and it works as expected due to `termDirStart` points to the `) DESC` part ....
I'll try to generalize this function to avoid copy/pasting
Could you suggest any example with `?` in `ORDER BY`? so I can start with test? :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rmannibucau (via GitHub)" <gi...@apache.org>.
rmannibucau commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3802018647
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
Review Comment:
maven profile = <property> and System.getProperty in code ;)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rmannibucau (via GitHub)" <gi...@apache.org>.
rmannibucau commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3802186239
##########
.github/workflows/ci.yml:
##########
@@ -14,26 +14,37 @@
# specific language governing permissions and limitations under the License.
#
name: Java CI
-on: [push]
+on:
+ push:
+ branches: [master]
Review Comment:
was thinking to 3.2.x for ex - dont think we maintain 2.2.x anymore
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4477333080
@solomax Did you try the docker compose + scripts I added to the branch? My Linux VDI was happy with 17/18 but might be good to check older versions as well... - the complexity is in all of these different dbms versions, I guess :(
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3803737872
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
Review Comment:
Sudo is not required after switching to the `gvenzl/oracle-xe`
Some tests are failing now
Will get full list (hopefully) and try to debug and/or will ask for the help :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5326426370
@rzo1 could you please add https://github.com/apache/openjpa/pull/144#issuecomment-5011202275 to the table?
And let's wait for @rmannibucau to resolve at least something from this huge table ....
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3802500440
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EnumValueHandler.java:
##########
@@ -116,8 +219,26 @@ public Object toDataStoreValue(ValueMapping vm, Object val, JDBCStore store) {
public Object toObjectValue(ValueMapping vm, Object val) {
if (val == null)
return null;
- if (_ordinal)
- return _vals[((Number) val).intValue()];
- return Enum.valueOf(vm.getType(), (String) val);
+ if (_useEnumeratedValue) {
+ initEnumeratedValueField(vm.getType());
+ Enum<?> result = _dbToEnum.get(val);
+ if (result == null && val instanceof Number) {
+ result = _dbToEnum.get(((Number) val).intValue());
+ }
+ if (result == null) {
+ result = _dbToEnum.get(val.toString());
+ }
+ return result;
Review Comment:
Understood
sorry for the noise!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3809672607
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypesafeCriteria.java:
##########
@@ -1781,5 +1789,168 @@ public void testIdClass() {
assertEquivalence(cq, jpql);
}
+
+ public void testLeft() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where left(p.name, 4) = 'John'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.left(c.get("name"), 4), "John"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testRight() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where RIGHT(p.name, 3) = 'Doe'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.right(c.get("name"), 3), "Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testReplace() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ String jpql = "select p from Person p where REPLACE(p.name, 'ohn', 'ack') = 'Jack Fitzgerald Doe'";
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.replace(c.get("name"), "ohn", "ack"), "Jack Fitzgerald Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ /**
+ * JPA 3.2 Criteria UNION must execute end-to-end and produce the
+ * same SQL as the JPQL UNION form. We don't compare row counts
+ * because TestTypesafeCriteria shares a static EMF with other test
+ * classes and we don't want to seed shared tables.
+ */
+ public void testCriteriaUnion() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 30));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.equal(r2.get("name"), "Ugo"));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> union = cb.union(q1, q2);
+ assertNotNull(em.createQuery(union).getResultList());
+ }
+
+ public void testCriteriaUnionAll() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 25));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.gt(r2.<Integer>get("age"), 30));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> unionAll = cb.unionAll(q1, q2);
+ assertNotNull(em.createQuery(unionAll).getResultList());
+ }
+
+ public void testCriteriaExcept() {
Review Comment:
Maybe `Configuration`/`OpenJPAConfiguration` can be extended to have something we can use (for. ex. `DBType`) ?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3414784383
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -107,6 +109,11 @@ public void testTruncate() {
@Test
public void testValidate() {
EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ DBDictionary dict = getDbDictionary(emf);
+ if (dict instanceof MySQLDictionary) {
Review Comment:
Hi, @solomax! I get a failed test on mysql:lts (docker, version 8.4.8-1.el9). Inspecting it, I found that the tinybit used for bool makes the testValidate fail because MysqlDbDictionary treats it as a number and then the actual test (should throw SchemaValidationException) fails.
Tested it again here without my exception and it fails.
I'm using maven:3-eclipse-temunin-17 (docker) to test the codebase, and mysql:sql (docker) as db target. Testing on pg (18, 17), h2 (2), hsql and mariadb (lts and latest) are all green here.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5037807906
+1 to merge and create a release candidate, but I guess it would be better to keep the commit history instead of squashing it to allow future fixes.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rmannibucau (via GitHub)" <gi...@apache.org>.
rmannibucau commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3426787818
##########
.github/workflows/ci.yml:
##########
@@ -21,19 +21,19 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- name: Setup Java JDK
- uses: actions/setup-java@v4
+ uses: actions/setup-java@v5
with:
- distribution: 'zulu'
- java-version: 11
+ distribution: 'temurin'
Review Comment:
any reason to not keep zulu?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3368876918
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java:
##########
@@ -3731,13 +3891,7 @@ public String[] getCreateTableSQL(Table table) {
checkNameLength(getFullIdentifier(table, false), maxTableNameLength, "long-table-name",
tableLengthIncludesSchema);
buf.append("CREATE TABLE ").append(tableName);
- if (supportsComments && table.hasComment()) {
- buf.append(" ");
Review Comment:
I remember it had something to do with spec compliant schema generation but it's from 3 months ago but we can restore it (no rights on that branch though). So feel free to do whatever it needed.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3487539922
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
The longest so far:
```
Time elapsed: 186247 s -- in org.apache.openjpa.persistence.criteria.TestJPQLSubquery
```
I'm still waiting ...
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3563619991
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
Had a look at this one. I debugged it by replaying the generated SQL against a plain in-memory HSQLDB (`jdbc:hsqldb:mem:`) from a small standalone `main()` and comparing the error codes / results of different cast variations:
```
ROUND(..., CAST(? AS DOUBLE)) -> -5563 incompatible data type in operation
ROUND(..., CAST(? AS INTEGER)) -> works
ROUND(..., ?) -> works
```
So your guess is exactly right: HSQLDB insists on an integer scale for `ROUND`.
Where the `CAST(? AS DOUBLE)` comes from: `HSQLDictionary` sets `requiresCastForMathFunctions = true`, and `DBDictionary.mathFunction()` then promotes *both* arguments to the common numeric type (`Filters.promote(Double, Integer)` → `double`) — even though the kernel (`Math` constructor) had already typed the scale argument as `Integer`.
There is a second problem hiding behind it though: with only the scale cast fixed, the query returns `21.0` instead of the expected `21.857`. The inner `CAST(SUM(t0.age) AS NUMERIC)` is the culprit — in HSQLDB, `NUMERIC` without precision/scale means **scale 0**, and the bare `?` divisor infers its type from the other operand, so `7.0` is truncated to `7` and the division is evaluated with scale 0:
```
CAST(SUM(age) AS NUMERIC) / ? -> 21
CAST(SUM(age) AS NUMERIC(40,20)) / ? -> 21.857142857142857...
```
Maybe something like this works — in `DBDictionary.mathFunction()`, keep a separate cast type for the ROUND scale:
```java
int type = 0;
int rtype = 0;
if (requiresCastForMathFunctions && (lc != rc
|| (lhs.isConstant() || rhs.isConstant()))) {
Class c = Filters.promote(lc, rc);
type = getJDBCType(JavaTypes.getTypeCode(c), false);
rtype = type;
if (type != Types.VARBINARY && type != Types.BLOB) {
castlhs = (lhs.isConstant() && rhs.isConstant()) || lc != c;
castrhs = (lhs.isConstant() && rhs.isConstant()) || rc != c;
}
}
boolean mod = "MOD".equals(op);
boolean power = "POWER".equals(op);
boolean round = "ROUND".equals(op);
if (round && castrhs) {
// the second argument of ROUND is an integer scale; casting it to
// the promoted numeric type of the first argument produces e.g.
// ROUND(x, CAST(? AS DOUBLE)), which databases reject
rtype = Types.INTEGER;
}
```
(and `appendCast(buf, rhs, rtype)` instead of `type` at the bottom of the method)
plus in `HSQLDictionary` (`appendLength` is only ever called from `appendCast`, so this does not affect DDL):
```java
@Override
protected void appendLength(SQLBuffer buf, int type) {
// HSQLDB gives CAST(x AS NUMERIC) without precision and scale a scale
// of 0 and silently truncates all fractional digits, so casts written
// for requiresCastForMathFunctions / requiresCastForComparisons would
// corrupt decimal values; always spell out precision and scale.
// 40/20 is an arbitrary but generous choice - adjust if needed
if (type == Types.NUMERIC || type == Types.DECIMAL) {
buf.append("(40,20)");
} else {
super.appendLength(buf, type);
}
}
```
With both changes `TestEJBQLFunction` on HSQLDB is down to a single remaining error (`testExtractWEEK` — HSQLDB does not know `EXTRACT(WEEK ...)`, it wants `WEEK_OF_YEAR`, that one needs a separate field-name mapping), and Derby stays green (64/64).
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
This one turned out to have the same root cause as the wrong ROUND *value* (see the other comment). Debugged it the same way — standalone `main()` against an in-memory HSQLDB, comparing variations:
```
SELECT 24 - 0.4 -> 23.6 (inline literals)
SELECT ? - ? (24, 0.4) -> 24 (!)
SELECT CAST(? AS NUMERIC) - ? (24, 0.4) -> 24 (!) <- this is what we generate
SELECT CAST(? AS NUMERIC(30,10)) - CAST(? AS ...) -> 23.6
```
OpenJPA renders JPQL literals as prepared-statement parameters, so the inline form never reaches the DB. For `24 - 0.4`, `mathFunction()` promotes `Long`/`BigDecimal` to `BigDecimal` and emits `CAST(? AS NUMERIC) - ?`. On HSQLDB that goes wrong twice:
1. `CAST(? AS NUMERIC)` without precision/scale is `NUMERIC` with **scale 0** → `24` stays `24`, and
2. the bare `?` infers its type from the other operand — also `NUMERIC` scale 0 — so `0.4` is truncated to `0`.
Result: `24 - 0 = 24`. So the `- 0.4` isn't ignored, it's truncated :)
The `appendLength` override from the ROUND comment fixes this one as well: the cast becomes `CAST(? AS NUMERIC(40,20)) - ?`, the bare parameter inherits the scaled type, and the result is `23.6`. The `CEILING`/`FLOOR` tests (`SUM(c.age) + 0.4` etc.) are covered by the same fix.
Re "how can this be debugged": I set `openjpa.Log=SQL=TRACE` to capture the generated SQL, then replayed it 1:1 in a small `main()` against `jdbc:hsqldb:mem:` and mutated the casts until the error code / wrong value pointed at the responsible piece.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3563214477
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
Another weird case for `HSSQL` is this one and alike
`- 0.4` part seems to be completely ignored
`Object result0 = em.createQuery("SELECT 24 - 0.4 AS s, COUNT(c) FROM CompUser c").getSingleResult();`
Results `24, 6` ....
how this can be debugged? :))
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4474927636
Hello @cristof, All
sorry for being silent for too long (burden at day -time job :(( )
I've noticed these WARNINGS:
```
Java Compiler Compiler Version 5.0 (Tree Builder)
(type "jjtree" with no arguments for help)
Warning: Bad option value in "-JDK_VERSION=17" will be ignored.
Reading from file /home/solomax/work/_oss/openjpa/openjpa-kernel/src/main/jjtree/org/apache/openjpa/kernel/jpql/JPQL.jjt . . .
File "Node.java" does not exist. Will create one.
File "JPQLTreeConstants.java" does not exist. Will create one.
File "JJTJPQLState.java" does not exist. Will create one.
Annotated grammar generated successfully in /home/solomax/work/_oss/openjpa/openjpa-kernel/target/javacc-1779085259067/node/JPQL.jj
Java Compiler Compiler Version 5.0 (Parser Generator)
(type "javacc" with no arguments for help)
Warning: Bad option value in "-JDK_VERSION=17" will be ignored.
Reading from file /home/solomax/work/_oss/openjpa/openjpa-kernel/target/javacc-1779085259067/node/JPQL.jj . . .
Warning: Choice conflict in (...)* construct at line 1053, column 17.
Expansion nested within construct and expansion following construct
have common prefixes, one of which is: "+"
Consider using a lookahead of 2 or more for nested expansion.
Warning: Choice conflict in (...)* construct at line 1062, column 17.
Expansion nested within construct and expansion following construct
have common prefixes, one of which is: "*"
Consider using a lookahead of 2 or more for nested expansion.
Warning: Choice conflict involving two expansions at
line 1533, column 12 and line 1534, column 12 respectively.
A common prefix is: "AVG" "("
Consider using a lookahead of 3 or more for earlier expansion.
Warning: Choice conflict involving two expansions at
line 1533, column 34 and line 1534, column 12 respectively.
A common prefix is: <IDENTIFIER>
Consider using a lookahead of 2 for earlier expansion.
File "TokenMgrError.java" does not exist. Will create one.
File "ParseException.java" does not exist. Will create one.
File "Token.java" does not exist. Will create one.
File "JavaCharStream.java" does not exist. Will create one.
Parser generated with 0 errors and 4 warnings.
```
Maybe `Choice conflict in` above need to be addressed?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3503067150
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
Another champion:
`Time elapsed: 350230 s <<< FAILURE! -- in org.apache.openjpa.persistence.criteria.TestTypesafeCriteria`
:(((
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3502992038
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
@cristof I need your help :)
`RIGHT`, `CURRENT_TIME` and `CEILING` are not supported by Oracle thus `org.apache.openjpa.persistence.criteria.TestTypesafeCriteria` is failing ...
Shall I exclude failing tests? or some additional fixes are required?
`EXCEPT` error above seems also be caused by absence/different syntax in Oracle ....
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3528669749
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
Yes, you are right: testBasicLocalTime wasn't skipped as testCurrentTimeReturnsSQLTypes. Added the skipping.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3695547787
##########
openjpa-kernel/src/main/jjtree/org/apache/openjpa/kernel/jpql/JPQL.jjt:
##########
@@ -1031,6 +1112,11 @@ void entity_type_comp() : { }
)
}
+void entity_id_or_version_comp() : { }
Review Comment:
Implementation seems to be adherent to spec (https://jakarta.ee/specifications/persistence/3.2/jakarta-persistence-spec-3.2#bnf), since it states that entity_id_or_version_comp() should be limited to = or <> comparisons.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3695533182
##########
openjpa-kernel/src/main/jjtree/org/apache/openjpa/kernel/jpql/JPQL.jjt:
##########
Review Comment:
Per spec (https://jakarta.ee/specifications/persistence/3.2/jakarta-persistence-spec-3.2#a4760), many of the referenced tokens are reserved identifiers, and it suggests reserved SQL words should also be avoided as identifiers.
Do you really think we should make some change about this behavior?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3781849935
##########
scripts/run-build-matrix.sh:
##########
@@ -0,0 +1,222 @@
+#!/bin/bash
+
+SCRIPT_ROOT=$(cd -- $(dirname "${0}") && pwd)
+PROJECT_ROOT="$(cd "${SCRIPT_ROOT}/.." && pwd)"
+declare -A FULL_DB_LIST=(
+ [h2]=embedded
+ [derby]=embedded
+ [hsqldb]=embedded
+ [mysql]=docker
+ [mariadb]=docker
+ [postgresql]=docker
+ [mssql]=docker
+ [herddb]=docker
+ [oracle]=docker
+)
+declare -A VERSIONS=(
+ [mysql]='8.0 8.4.8 9.4.0'
+ [postgresql]='11 16 18'
+)
+COLOR_RED="\033[1;31m"
+COLOR_GREEN="\033[1;32m"
+COLOR_RESET="\033[0m"
+MATRIX=${!FULL_DB_LIST[@]}
+EXCLUDE=''
+REPORT_DIR=.report
+START_WITH=''
+declare -a JPROPS=()
+OFFLINE=
+
+usage() {
+ echo "usage ${0} [-s|--start-with DB_ALIAS] [-r|--report-dir DIR] [-m|--matrix user_matrix] [-e|--exclude exclude_list] [-o|--offline] [-h|--help]"
+ echo -e "\t-s|--start-with DB_ALIAS -- option to skip some databases in the begininning (continue from) [def: '${START_WITH}']"
+ echo -e "\t-r|--report-dir DIR -- the folder with report and logs (will be autocreated) [def: '${REPORT_DIR}']"
+ echo -e "\t-m|--matrix user_matrix -- test matrix in the format 'db1:ver1,ver2;db2;db3:ver3;...' [def db list: ${MATRIX[@]}]"
+ echo -e "\ti.e DB delimiter is ';', in case version(s) should be specified it MUST follow after ':' and have ',' as delimiter"
+ echo -e "\texample: \"-m=oracle\" or \"--matrix='oracle;mysql:8.0'\" or \"--matrix 'postgresql:16,18;mysql:9.4.0'\""
+ echo -e "\t-e|--exclude exclude_list -- exclude DBs from run 'db1;db2;db3;...' [def exclude list: ${EXCLUDE}]"
+ echo -e "\t-o|--offline -- will run tests in offline mode"
+ echo -e "\t-h|--help -- this help message"
+ echo
+ echo -e "\tPlease NOTE: lists for [-m|--matrix user_matrix] [-e|--exclude exclude_list] params should be 'singel_quoted'"
+ echo -e "\tPlease NOTE: additional build parameters can be passed via '-D*' for ex. '-Ddocker.cpus=4' ..."
+}
+
+user_matrix=''
+
+while [[ $# -gt 0 ]]; do
+ case ${1} in
+ -s=*|--start-with=*)
+ START_WITH="${1#*=}"
+ shift
+ ;;
+ -s|--start-with)
+ START_WITH="${2}"
+ shift 2
+ ;;
+ -r=*|--report-dir=*)
+ REPORT_DIR="${1#*=}"
+ shift
+ ;;
+ -r|--report-dir)
+ REPORT_DIR="${2}"
+ shift 2
+ ;;
+ -m=*|--matrix=*)
+ user_matrix="${1#*=}"
+ shift
+ ;;
+ -m|--matrix)
+ user_matrix="${2}"
+ shift 2
+ ;;
+ -e=*|--exclude=*)
+ EXCLUDE="${1#*=}"
+ shift
+ ;;
+ -e|--exclude)
+ EXCLUDE="${2}"
+ shift 2
+ ;;
+ -o|--offline)
+ OFFLINE=-o
+ shift
+ ;;
+ -h|--help)
+ usage
+ exit 0
+ shift
+ ;;
+ -D*)
+ JPROPS+=("${1}")
+ shift
+ ;;
+ *)
+ echo "Unknown option ${1}"
+ usage
+ exit 1
+ ;;
+ esac
+done
+
+stopAll() {
+ for profile in ${MATRIX[@]}; do
+ if [[ "${FULL_DB_LIST[${profile}]}" == "docker" ]]; then
+ mvn -N -Ptest-${profile}-docker -Ddocker.stopNamePattern=${profile:0:8}* docker:stop -Ddocker.showLogs
+ fi
+ done
+}
+
+cd "${PROJECT_ROOT}"
+
+stopAll
+
+if [[ -n "${user_matrix}" ]]; then
+ MATRIX=()
+ IFS=';' read -r -a dbvers <<< "${user_matrix}"
+ for dbver in ${dbvers[@]}; do
+ if [[ -z "${dbver}" ]]; then
+ continue
+ fi
+ IFS=':' read -r -a db_vers <<< "${dbver}"
+ if [[ ${#db_vers[@]} == 1 ]]; then
+ db=${db_vers[0]}
+ vers=''
+ else
+ db=${db_vers[0]}
+ vers=${db_vers[1]}
+ fi
+ MATRIX+=(${db})
+ if [[ -n "${vers}" ]]; then
+ VERSIONS+=([${db}]=$(echo -n "${vers}" | sed -r 's/[,]/ /g'))
+ fi
+ done
+fi
+
+stopAll
+
+REPORT_DIR="${SCRIPT_ROOT}/${REPORT_DIR}"
+REPORT_FILE="${REPORT_DIR}/report.txt"
+if [[ -d "${REPORT_DIR}" ]]; then
+ rm -rf "${REPORT_DIR}"/*
+else
+ mkdir -p "${REPORT_DIR}"
+fi
+echo "" > "${REPORT_FILE}"
+
+do_test() {
+ local profile=${1}
+ local log=${2}
+ local -n params=${3}
+ local status="${COLOR_RED}Failed${COLOR_RESET}"
+ rm -rf openjpa-xmlstore/jdbc:*
+
+ if [[ "${profile}" == *docker ]]; then
+ set -x
+ mvn -N -P${profile} "${params[@]}" docker:start -Ddocker.showLogs
+ local retCode=$?
+ set +x
+ if [[ ${retCode} != 0 ]]; then
+ echo "Failed -- ${log} (can't start docker)" |tee -a ${REPORT_FILE}
+ return 1
+ fi
+ fi
+ set -x
+ mvn clean install -P${profile} "${params[@]}" "${JPROPS[@]}" -Drat.skip ${OFFLINE} &> ${REPORT_DIR}/build_${log}.log
+ local retCode=$?
+ set +x
+ if [[ ${retCode} == 0 ]]; then
+ status="${COLOR_GREEN}Passed${COLOR_RESET}"
+ fi
+ if [[ "${profile}" == *docker ]]; then
+ set -x
+ mvn -N -P${profile} "${params[@]}" docker:stop -Ddocker.showLogs
+ set +x
+ fi
+ echo -e "${status} -- ${log}"
+ echo -e "${status} -- ${log}" >> ${REPORT_FILE}
+ echo " ----------------- "
+}
+
+test_profile() {
+ local mode=${1}
+ local profile=${2}
+ if [[ -n "${START_WITH}" ]]; then
+ if [[ "${profile}" == "${START_WITH}" ]]; then
+ START_WITH=""
+ else
+ echo "Skipping ${profile} ..."
+ continue
Review Comment:
fixed
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3781837523
##########
openjpa-integration/tck/run-tck32.sh:
##########
@@ -0,0 +1,210 @@
+#!/bin/bash
+#
+# 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.
+#
+
+TCK_VERSION="${TCK_VERSION:-3.2.0}"
+TCK_BASE="${TCK_VERSION:0:3}"
+
+SCRIPT_ROOT=$(cd -- $(dirname "${0}") && pwd)
+PROJECT_ROOT="$(cd "${SCRIPT_ROOT}/../.." && pwd)"
+
+# derby is removed for now
+# mysql 8.0 is broken! db.delimiter='!' breaks connection
+declare -A FULL_DB_LIST=(
+ [mysql]=mysql
+ [postgresql]=postgresql
+ [mssql]=mssqlserver
+ [oracle]=oracle
+)
+
+declare -A VERSIONS=(
+ [mysql]='8.4.8' # 8.4.8 9.4.0
+ [postgresql]='16'
+)
+
+#
+# Script to download, setup and run the JPA 3.2 TCK against OpenJPA
+# using DB selected.
+#
+# Usage:
+# ./run-tck32.sh # Run full TCK against postgres:16
+# DB_VERSION=18 ./run-tck32.sh # Run full TCK against postgres:18
+# DB_TYPE=mysql ./run-tck32.sh # Run full TCK against mysql:8.4.8
+# DB_HOST=myhost:5432 ./run-tck32.sh # Custom DB host
+# OPENJPA_VERSION=4.2.0-SNAPSHOT ./run-tck32.sh # Custom OpenJPA version
+#
+# Prerequisites:
+# - OpenJPA must be built and installed in local Maven repo
+# (run 'mvn install -DskipTests' from the project root)
+# - Java 17+ and Maven 3.x
+#
+
+set -e
+
+# Check required commands
+MISSING=""
+for cmd in java mvn curl unzip grep sed; do
+ if ! command -v "$cmd" &>/dev/null; then
+ MISSING="${MISSING} - ${cmd}\n"
+ fi
+done
+if [[ -n "$MISSING" ]]; then
+ echo "ERROR: The following required commands are not available:"
+ echo -e "$MISSING"
+ echo "Please install them before running this script."
+ exit 1
+fi
+
+stopAll() {
+ for profile in ${!FULL_DB_LIST[@]}; do
+ echo "Stopping dockerized ${profile}"
+ mvn -N -Ptest-${profile}-docker -f ${PROJECT_ROOT} -Ddocker.stopNamePattern=${profile:0:8}* docker:stop -Ddocker.showLogs
+ done
+}
+
+stopAll
+
+TCK_URL="https://download.eclipse.org/jakartaee/persistence/${TCK_BASE}/jakarta-persistence-tck-${TCK_VERSION}.zip"
+TCK_DIR="${SCRIPT_ROOT}/target/tck32"
+TCK_ZIP="${TCK_DIR}/jakarta-persistence-tck-${TCK_VERSION}.zip"
+TCK_HOME="${TCK_DIR}/persistence-tck"
+OPENJPA_VERSION="${OPENJPA_VERSION:-4.2.0-SNAPSHOT}"
+START_DOCKER=
+
+if [[ -z "${DB_HOST}" ]]; then
+ START_DOCKER=1
+fi
+
+DB_TYPE="${DB_TYPE:-postgresql}"
+DB_HOST="${DB_HOST:-localhost:5555}"
+DB_USER="${DB_USER:-tcktest}"
+DB_PASSWORD="${DB_PASSWORD:-tcktest}"
+DB_NAME="${DB_NAME:-tcktest}"
+DB_URL=""
+declare -a JPROPS=()
+
+DB_HOST_ONLY="${DB_HOST%%:*}"
+DB_PORT="${DB_HOST##*:}"
+
+TCK_DB_TYPE="${FULL_DB_LIST[${DB_TYPE}]}"
+
+setProps() {
+ local ver="${VERSIONS[${DB_TYPE}]}"
+ if [[ -n "${DB_VERSION}" ]]; then
+ ver="${DB_VERSION}"
+ fi
+ if [[ -n "${VERSIONS[${DB_TYPE}]}" ]]; then
+ JPROPS+=("-D${DB_TYPE}.server.version=${ver}")
+ fi
+
+ case ${DB_TYPE} in
+ mysql)
+ DB_URL="jdbc:mysql://${DB_HOST}/${DB_NAME}?useSSL=false&allowPublicKeyRetrieval=true&transformedBitIsBoolean=true"
+ ;;
+ postgresql)
+ DB_URL="jdbc:postgresql://${DB_HOST}/${DB_NAME}"
+ ;;
+ mssql)
+ DB_NAME=""
+ DB_URL="jdbc:sqlserver://${DB_HOST};sendTimeAsDatetime=false;trustServerCertificate=true"
+ ;;
+ oracle)
+ JPROPS+=("-Dopenjpa.oracle.SID=${DB_NAME}")
+ DB_NAME="XE"
+ DB_URL="jdbc:oracle:thin:@${DB_HOST}:${DB_NAME}"
+ ;;
+ esac
+ JPROPS+=("-Ddocker.external.${DB_TYPE}.port=${DB_PORT}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.dbname=${DB_NAME}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.username=${DB_USER}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.password=${DB_PASSWORD}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.url=${DB_URL}")
+}
+
+setProps
+
+if [[ -n "${START_DOCKER}" ]]; then
+ echo "Starting dockerized ${DB_TYPE}"
+ mvn -N -f ${PROJECT_ROOT} -Ptest-${DB_TYPE}-docker "${JPROPS[@]}" docker:start -Ddocker.showLogs
+fi
+
+GF_VERSION="${GF_VERSION:-8.0.0}"
+
+echo "=== JPA ${TCK_BASE} TCK Runner for OpenJPA ==="
+echo "OpenJPA version: ${OPENJPA_VERSION}"
+echo "TCK version: ${TCK_VERSION}"
+echo "GlassFish: ${GF_VERSION}"
+echo "Database: ${DB_TYPE} (${DB_HOST}/${DB_NAME})"
+echo ""
+
+# Step 1: Download TCK if not present
+mkdir -p "${TCK_DIR}"
+if [[ ! -f "${TCK_ZIP}" ]]; then
+ echo "Downloading JPA ${TCK_BASE} TCK..."
+ curl -sL -o "${TCK_ZIP}" "${TCK_URL}"
Review Comment:
done
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5190084736
BTW
Just noticed these warnings in build log:
```
Reading from file /home/runner/work/openjpa/openjpa/openjpa-kernel/target/javacc-1785507996706/node/JPQL.jj . . .
Warning: Choice conflict in (...)* construct at line 1053, column 17.
Expansion nested within construct and expansion following construct
have common prefixes, one of which is: "+"
Consider using a lookahead of 2 or more for nested expansion.
Warning: Choice conflict in (...)* construct at line 1062, column 17.
Expansion nested within construct and expansion following construct
have common prefixes, one of which is: "*"
Consider using a lookahead of 2 or more for nested expansion.
Warning: Choice conflict involving two expansions at
line 1533, column 12 and line 1534, column 12 respectively.
A common prefix is: "AVG" "("
Consider using a lookahead of 3 or more for earlier expansion.
Warning: Choice conflict involving two expansions at
line 1533, column 34 and line 1534, column 12 respectively.
A common prefix is: <IDENTIFIER>
Consider using a lookahead of 2 for earlier expansion.
```
Is this something need to be addressed?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3761215139
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaTool.java:
##########
@@ -479,71 +509,140 @@ protected void deleteTableContents()
Collection<Table> tables = new LinkedHashSet<>();
for (Schema schema : schemas) {
Table[] ts = schema.getTables();
- for (Table t : ts) {
- tables.add(t);
- }
+ Collections.addAll(tables, ts);
}
Table[] tableArray = tables.toArray(new Table[tables.size()]);
Connection conn = _ds.getConnection();
+ // Truncate is a best-effort operation: the repo SchemaGroup may
+ // declare tables the dialect never actually created (e.g.
+ // OPENJPA_SEQUENCE_TABLE on dialects that prefer native sequences,
+ // or tables in other schemas). Log missing-table errors instead of
+ // aborting.
+ boolean savedIgnore = _ignoreErrs;
+ _ignoreErrs = true;
try {
String[] sql = _conf.getDBDictionaryInstance()
.getDeleteTableContentsSQL(tableArray, conn);
if (!executeSQL(sql)) {
_log.warn(_loc.get("delete-table-contents"));
}
} finally {
+ _ignoreErrs = savedIgnore;
closeConnection(conn);
}
}
- protected void executeScript() throws SQLException {
- if (_scriptToExecute == null) {
- _log.warn(_loc.get("generating-execute-script-not-defined"));
- return;
+ private BufferedReader getScriptReader() throws IOException {
+ BufferedReader reader = null;
+ if (_scriptReader != null) {
+ reader = (_scriptReader instanceof BufferedReader br) ? br : new BufferedReader(_scriptReader);
+ } else {
+ URL url = null;
+ // Try file: URI or absolute path first
+ if (_scriptToExecute.startsWith("file:")) {
+ try {
+ url = new URI(_scriptToExecute).toURL();
+ } catch (Exception e) {
+ // fall through to classloader lookup
+ }
+ } else {
+ File f = new File(_scriptToExecute);
+ if (f.isAbsolute() && f.exists()) {
+ url = f.toURI().toURL();
+ }
+ }
+ // Fall back to classloader resource lookup
+ if (url == null) {
+ url = _conf.getClassResolverInstance()
+ .getClassLoader(SchemaTool.class, null)
+ .getResource(_scriptToExecute);
+ }
+ if (url == null) {
+ _log.error(_loc.get("generating-execute-script-not-found", _scriptToExecute));
+ return null;
+ }
+ _log.info(_loc.get("generating-execute-script", _scriptToExecute));
+ reader = new BufferedReader(new InputStreamReader(url.openStream()));
}
+ return reader;
+ }
- URL url = AccessController.doPrivileged(
- J2DoPrivHelper.getResourceAction(_conf.getClassResolverInstance().
- getClassLoader(SchemaTool.class, null), _scriptToExecute));
-
- if (url == null) {
- _log.error(_loc.get("generating-execute-script-not-found", _scriptToExecute));
+ protected void executeScript() throws SQLException {
+ if (_scriptReader == null && StringUtil.isBlank(_scriptToExecute)) {
+ _log.warn(_loc.get("generating-execute-script-not-defined"));
return;
}
- _log.info(_loc.get("generating-execute-script", _scriptToExecute));
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new InputStreamReader(url.openStream()));
- String sql;
+ try (BufferedReader reader = getScriptReader()) {
+ if (reader == null) {
+ return;
+ }
+ String line;
List<String> script = new ArrayList<>();
- while ((sql = reader.readLine()) != null) {
- sql = sql.trim();
- if (sql.startsWith("--") || sql.startsWith("/*") || sql.startsWith("//")) {
+ StringBuilder stmt = new StringBuilder();
+ AtomicBoolean insideMultilineComments = new AtomicBoolean(false);
+ Function<String, String> stripComments = (str) -> {
Review Comment:
Commited the suggested fix with a associated test, but I think this should be addressed better in the future, maybe with a regex parsing of the scripts.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3437291097
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
Hello @cristof, @rzo1,
I need help
This test still failing at `Oracle` due to `BOOLEAN` was introduced in `Oracle-23` only ...
BUT
If I'm changing this `BOOLEAN` to `INT` - `validate()` doesn't throw ...
Maybe you can suggest how to fix it?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4720557780
I'll start another thread :)
I would like to propose this script https://github.com/apache/openjpa/blob/9da3e207072a3b5cf553e8a7f17cd41f609839bc/scripts/complex_test.sh
As drop-in replacement for https://github.com/apache/openjpa/blob/9da3e207072a3b5cf553e8a7f17cd41f609839bc/scripts/run-build-matrix.sh
IMO it is better because:
- it uses docker configs inlined into `pom.xml`
- it is more flexible: any available versions can be tested
WDYT?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4726762509
@ilgrosso for whatever reason this `KubernetesTCPRemoteCommitProviderTest.addresses:165 expected:<2> but was:<0>` test is unstable ...
Could you please take a look at it?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rmannibucau (via GitHub)" <gi...@apache.org>.
rmannibucau commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3426797320
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/BatchingPreparedStatementManagerImpl.java:
##########
@@ -254,13 +254,22 @@ private void flushSingleRow(RowImpl row, PreparedStatement ps)
row.flush(ps, _dict, _store);
int count = executeUpdate(ps, row.getSQL(_dict), row);
if (count != 1) {
- logSQLWarnings(ps);
- Object failed = row.getFailedObject();
- if (failed != null)
- _exceptions.add(new OptimisticException(failed));
- else if (row.getAction() == Row.ACTION_INSERT)
- throw new SQLException(_loc.get("update-failed-no-failed-obj",
- String.valueOf(count), row.getSQL(_dict)).getMessage());
+ // For DELETE actions, tolerate count=0 because the row may
+ // have already been removed by a database-level ON DELETE
+ // CASCADE triggered by a related row's deletion.
+ if (count == 0 && row.getAction() == Row.ACTION_DELETE) {
Review Comment:
is this by spec? how do I know my delete was a noop as a caller now?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4477309050
`Postgres 16` also fails :( Same exception
I'll try to check
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof merged PR #144:
URL: https://github.com/apache/openjpa/pull/144
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3368877090
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractBrokerFactory.java:
##########
@@ -787,7 +809,7 @@ boolean syncWithManagedTransaction(BrokerImpl broker, boolean begin) {
public Collection<Broker> getOpenBrokers() {
return Collections.unmodifiableCollection(_brokers);
}
-
+
Review Comment:
Same as below (no rights on the branch). Feel free.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3559223756
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
Thanks @rzo1,
mssql is green :)
I'll try to investigate other issues :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4998635658
Hello All,
here are results of my TCK run:
`Postgres:11` can't be used due to `procedure can't have OUT param`
At `Postgres:16` following errors are reported:
```
SEVERE: Unexpected exception occurred
<openjpa-4.2.0-SNAPSHOT-r4f1cb50M fatal general error> org.apache.openjpa.persistence.PersistenceException: class java.util.Date cannot be cast to class java.sql.Date (java.util.Date is in module java.base of loader 'bootstrap'; java.sql.Date is in module java.sql of loader 'platform')
..........................
..........................
..........................
Caused by: java.lang.ClassCastException: class java.util.Date cannot be cast to class java.sql.Date (java.util.Date is in module java.base of loader 'bootstrap'; java.sql.Date is in module java.sql of loader 'platform')
at org.apache.openjpa.jdbc.sql.DBDictionary.setTyped(DBDictionary.java:1693)
at org.apache.openjpa.jdbc.sql.PostgresDictionary.setTyped(PostgresDictionary.java:461)
at org.apache.openjpa.jdbc.sql.RowImpl.flush(RowImpl.java:1002)
[ERROR] Tests run: 14, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 3.468 s <<< FAILURE! -- in ee.jakarta.tck.persistence.core.annotations.id.Client
[ERROR] ee.jakarta.tck.persistence.core.annotations.id.Client.FieldUtilDateIdTest -- Time elapsed: 0.222 s <<< ERROR!
java.lang.Exception: FieldUtilDateIdTest failed
at ee.jakarta.tck.persistence.core.annotations.id.Client.FieldUtilDateIdTest(Client.java:389)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
[ERROR] ee.jakarta.tck.persistence.core.annotations.id.Client.PropertyUtilDateIdTest -- Time elapsed: 0.234 s <<< ERROR!
java.lang.Exception: PropertyUtilDateIdTest failed
at ee.jakarta.tck.persistence.core.annotations.id.Client.PropertyUtilDateIdTest(Client.java:718)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
```
```
[INFO] --- failsafe:3.2.5:integration-test (persistence-tests-2) @ persistence-tck-runner ---
[INFO] Failsafe report directory: /home/solomax/work/_oss/openjpa/openjpa-integration/tck/target/tck32/persistence-tck/bin/target/failsafe-reports
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running ee.jakarta.tck.persistence.se.entityManagerFactory.Client2
11 WARN [main] openjpa.Runtime - The configuration property named "openjpa.version" was not recognized and will be ignored, although the name closely matches a valid property called "openjpa.Log".
25 ERROR [main] openjpa.Runtime - A fatal error occurred while trying to create the required validation provider.java.lang.RuntimeException: A default ValidatorFactory could not be created.
at org.apache.openjpa.persistence.validation.ValidatorImpl.initialize(ValidatorImpl.java:129)
at org.apache.openjpa.persistence.validation.ValidatorImpl.<init>(ValidatorImpl.java:91)
at org.apache.openjpa.persistence.validation.ValidationUtils.setupValidation(ValidationUtils.java:99)
..........................
..........................
..........................
Caused by: java.lang.RuntimeException: A default ValidatorFactory could not be created.
at org.apache.openjpa.persistence.validation.ValidatorImpl.initialize(ValidatorImpl.java:129)
at org.apache.openjpa.persistence.validation.ValidatorImpl.<init>(ValidatorImpl.java:91)
at org.apache.openjpa.persistence.validation.ValidationUtils.setupValidation(ValidationUtils.java:99)
... 77 more
```
I'll try to investigate and improve script to work with some other DBs
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5011202275
It seems some errors in MySQL TCK tests are caused by:
```
Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: Data truncation: Data too long for column 'CHARDATA' at row 1 {prepstmnt 2112012700 INSERT INTO DATATYPES (id, BOOLEANDATA, BYTEARRAYDATA, BYTEDATA, CHARARRAYDATA, CHARDATA, DBLDATA, ENUMSDATA, FLOATDATA, INTDATA, INTDATA2, LONGDATA, SHORTDATA) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)} [code=1406, state=22001]
at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:219)
at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:195)
at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator$LoggingConnection$LoggingPreparedStatement.executeUpdate(LoggingConnectionDecorator.java:1188)
at org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:308)
at org.apache.openjpa.jdbc.kernel.JDBCStoreManager$CancelPreparedStatement.executeUpdate(JDBCStoreManager.java:1867)
```
While trying to persist entity with:
```java
@Column(name = "CHARDATA")
protected char characterData;
```
Table is create with:
```sql
CREATE TABLE DATATYPES (ID INTEGER NOT NULL, BOOLEANDATA SMALLINT NULL, CHARDATA CHAR NULL, SHORTDATA SMALLINT NULL, INTDATA INTEGER NULL, INTDATA2 INTEGER NULL, LONGDATA NUMERIC NULL, DBLDATA DOUBLE PRECISION NULL, FLOATDATA REAL NULL, ENUMODATA INTEGER NULL, ENUMSDATA VARCHAR(25), BYTEDATA SMALLINT NULL, TRANS SMALLINT NULL, BYTEARRAYDATA BLOB, CHARARRAYDATA VARCHAR(448), CONSTRAINT PK_DATATYPES PRIMARY KEY (ID) ) ENGINE=innoDB DEFAULT CHARSET=latin1 !
```
java oblect is created with:
```java
char[] cArray = { 'a' };
byte[] bArray = { (byte) 100 };
d1 = new DataTypes(1, false, (byte) 100, 'a', (short) 100, 300, 600L, 50D, 1.0F, cArray, bArray);
```
Something weird :(((
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3761875623
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Ceiling.java:
##########
@@ -55,7 +59,13 @@ protected Class getType(Class c) {
@Override
protected String getOperator() {
- return "CEILING";
+ return operator;
+ }
+
+ @Override
+ public void appendTo(Select sel, ExpContext ctx, ExpState state, SQLBuffer sql, int index) {
Review Comment:
This was intended behavior meant to allow support of different DBs.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3771753386
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java:
##########
@@ -309,7 +325,7 @@ public OpenJPAQuery<X> setParameters(Map params) {
@Override
public <T> Parameter<T> getParameter(String name, Class<T> type) {
Parameter<?> param = getParameter(name);
- if (param.getParameterType().isAssignableFrom(type))
+ if (!param.getParameterType().isAssignableFrom(type))
Review Comment:
Fixed.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3700878512
##########
openjpa-integration/tck/run-tck32.sh:
##########
@@ -0,0 +1,210 @@
+#!/bin/bash
+#
+# 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.
+#
+
+TCK_VERSION="${TCK_VERSION:-3.2.0}"
+TCK_BASE="${TCK_VERSION:0:3}"
+
+SCRIPT_ROOT=$(cd -- $(dirname "${0}") && pwd)
+PROJECT_ROOT="$(cd "${SCRIPT_ROOT}/../.." && pwd)"
+
+# derby is removed for now
+# mysql 8.0 is broken! db.delimiter='!' breaks connection
+declare -A FULL_DB_LIST=(
+ [mysql]=mysql
+ [postgresql]=postgresql
+ [mssql]=mssqlserver
+ [oracle]=oracle
+)
+
+declare -A VERSIONS=(
+ [mysql]='8.4.8' # 8.4.8 9.4.0
+ [postgresql]='16'
+)
+
+#
+# Script to download, setup and run the JPA 3.2 TCK against OpenJPA
+# using DB selected.
+#
+# Usage:
+# ./run-tck32.sh # Run full TCK against postgres:16
+# DB_VERSION=18 ./run-tck32.sh # Run full TCK against postgres:18
+# DB_TYPE=mysql ./run-tck32.sh # Run full TCK against mysql:8.4.8
+# DB_HOST=myhost:5432 ./run-tck32.sh # Custom DB host
+# OPENJPA_VERSION=4.2.0-SNAPSHOT ./run-tck32.sh # Custom OpenJPA version
+#
+# Prerequisites:
+# - OpenJPA must be built and installed in local Maven repo
+# (run 'mvn install -DskipTests' from the project root)
+# - Java 17+ and Maven 3.x
+#
+
+set -e
+
+# Check required commands
+MISSING=""
+for cmd in java mvn curl unzip grep sed; do
+ if ! command -v "$cmd" &>/dev/null; then
+ MISSING="${MISSING} - ${cmd}\n"
+ fi
+done
+if [[ -n "$MISSING" ]]; then
+ echo "ERROR: The following required commands are not available:"
+ echo -e "$MISSING"
+ echo "Please install them before running this script."
+ exit 1
+fi
+
+stopAll() {
Review Comment:
@rmannibucau (this one is mine :))))
this call was added to stop all stalled dockers from previous runs (better to use `trap` and perform clean-up, but this `dirty` solution much easier :)))
I would leave it as-is but also can change if you insist :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3800745569
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
Review Comment:
@rmannibucau I can use temporary folder created with `mktemp -d` for Oracle DB (this way it can't be reused, but there will be no need in sudo ...
WDYT?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3802190608
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java:
##########
@@ -57,9 +58,17 @@ public void tearDown() throws Exception {
* @param sqlExp the SQL expression. E.g., "SELECT FOO .*"
*/
public void assertSQL(String sqlExp) {
+ DBDictionary dict = getDBDictionary();
for (String statement : sql) {
- if (statement.matches(sqlExp))
+ if (statement.matches(sqlExp)) {
+ return;
+ }
+ String noDelims = statement
Review Comment:
Different DBs have slightly different reserved keywords list. Plus for whatever reason keyword escaping is something treated as unnecessary
I do remember I saw test creating DB table with name `TABLE` and checking it wasn't escaped ...
there are lots of tests checking SQL matches exactly and they were failing
I can add method comment like above
Would it be sufficient?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5325916594
Here is a table @solomax for better overview, with links into each discussion. Might be helpful — we can update it automatically if needed.
56 unresolved review threads, excluding the `EnumValueHandler` `@EnumeratedValue` thread currently being worked on.
| ID | Link | Title | Comment | Author |
| --- | --- | --- | --- | --- |
| 3426797320 | [3426797320](https://github.com/apache/openjpa/pull/144#discussion_r3426797320) | Silently swallowed no-op batched delete result | is this by spec? how do I know my delete was a noop as a caller now? | rmannibucau |
| 3426807128 | [3426807128](https://github.com/apache/openjpa/pull/144#discussion_r3426807128) | Null state manager cases should throw instead of skip | wonder if these null cases shouldn't throw, means enhancement is broken or setup (agent) is broken no? | rmannibucau |
| 3426812145 | [3426812145](https://github.com/apache/openjpa/pull/144#discussion_r3426812145) | Possible missed loop case in row flush handling | same, to review if we don't loop a case there | rmannibucau |
| 3682999074 | [3682999074](https://github.com/apache/openjpa/pull/144#discussion_r3682999074) | New JPQL keywords no longer usable as aliases | **(medium)** `identification_variable()` only accepts `<IDENTIFIER>`, so every newly introduced token (ID, VERSION, RIGHT, ON, NULLS, FIRST, LAST, CAST, STRING, UNION, INTERSECT, EXCEPT, TREAT, ...) can no longer be used as an identification variable or result alias. Existing queries like `SELECT e.id AS id ... ORDER BY id` or aliases named `first`/`on` now fail to parse - a backward-compat regression worth documenting or mitigating with soft keywords. (re line 1560, outside the diff hunks) | rmannibucau |
| 3682999176 | [3682999176](https://github.com/apache/openjpa/pull/144#discussion_r3682999176) | ID()/VERSION() limited to equality against parameters | **(medium)** `entity_id_or_version_comp()` only allows `ID(x)`/`VERSION(x)` compared with `=`/`<>` against an input parameter. Spec-legal forms like `ID(e) = 5`, `VERSION(e) >= :v` or `ID(a) = ID(b)` do not parse - intentional first step, or should these functions be reachable from the general comparison/arithmetic productions? | rmannibucau |
| 3682999345 | [3682999345](https://github.com/apache/openjpa/pull/144#discussion_r3682999345) | Broadened auto-flush before every query hurts perf | **(medium)** With FLUSH_TRUE (default FlushModeType.AUTO) this now flushes before every query as soon as anything in the context is dirty, and the `flush == FLUSH_TRUE` addition at line 1033 also overrides the IgnoreChanges setting. That defeats the access-path optimization and can be a real perf regression in write-heavy transactions - can the broadened check be limited to types related to the query access path, or guarded by a compatibility flag? | rmannibucau |
| 3682999520 | [3682999520](https://github.com/apache/openjpa/pull/144#discussion_r3682999520) | Full context flush after in-memory bulk update/delete | **(medium)** The new `_broker.flush()` after in-memory bulk delete (and update at line 1156) flushes the entire persistence context as a side effect of `executeUpdate()`, changing when unrelated pending changes hit the database (locks, triggers, constraint timing). Is flushing only the affected instances feasible, or is the full flush deliberate? | rmannibucau |
| 3682999635 | [3682999635](https://github.com/apache/openjpa/pull/144#discussion_r3682999635) | Transient object wrongly assumed detached in flush check | **(medium)** This early-return treats any unmanageable instance of a known entity type as detached without verifying it was ever persisted, so a truly transient unenhanced object referenced without cascade now passes the check and fails later (or silently persists a broken FK). Line 824 also adds `_broker.isDetached(obj, true)`, a DB round-trip inside the flush path for every manageable object without a state manager. Can both paths at least verify a non-null/assigned identity before assuming detached? | rmannibucau |
| 3682999733 | [3682999733](https://github.com/apache/openjpa/pull/144#discussion_r3682999733) | Embedded converter override leaks to shared embeddable meta | **(medium)** `propagateEmbeddedConverters()` sets the converter on the shared embeddable ClassMetaData. If two entities embed the same embeddable but only one declares `@Convert(attributeName=...)`, the override leaks to all other usages (last-resolved wins). Should the override only apply to the per-embedding `embeddedMeta` copy? | rmannibucau |
| 3682999838 | [3682999838](https://github.com/apache/openjpa/pull/144#discussion_r3682999838) | Unsafe publication of cached AttributeConverter instance | **(medium)** The converter instance is now created once and cached in a non-volatile field without synchronization; FieldMetaData is shared across brokers/threads, so this is unsafe publication and a behavior change (previously a new converter instance per conversion, now one shared instance that must be thread-safe). Consider thread-safe caching and documenting that AttributeConverters are treated as shared/stateless. | rmannibucau |
| 3683000132 | [3683000132](https://github.com/apache/openjpa/pull/144#discussion_r3683000132) | extractSchemaGenObjects mutates caller's properties map | **(medium)** `extractSchemaGenObjects` calls `map.remove(key)` on the caller-supplied properties map - this mutates user configuration and throws UnsupportedOperationException for unmodifiable maps (e.g. `Map.of(...)` passed to `createEntityManagerFactory`). Can the Writer/Reader values be captured without mutating the input? | rmannibucau |
| 3683000248 | [3683000248](https://github.com/apache/openjpa/pull/144#discussion_r3683000248) | In-memory ID(), set ops and nullPrecedence unimplemented | **(medium)** `getNativeObjectId` returns the same `GetObjectId` as `getObjectId`, which evaluates to the internal ObjectId wrapper (e.g. LongId), not the raw PK value - so an in-memory `ID(e) = :id` comparison against the plain key may never match; should it unwrap like the JDBC side? Similarly `setOperands`/`setOperationType` and `nullPrecedence` appear consumed only by the JDBC store, so in-memory execution of UNION/INTERSECT/EXCEPT or NULLS FIRST/LAST silently produces wrong results - should the in-memory path reject or implement them? | rmannibucau |
| 3683000358 | [3683000358](https://github.com/apache/openjpa/pull/144#discussion_r3683000358) | hasEmbeddableAnnotation relies on annotation simple name | **(low)** `hasEmbeddableAnnotation` matches any annotation whose simple name is "Embeddable" (from any package) and misses embeddables declared only in orm.xml - would checking the repository metadata (e.g. `fmd.getEmbeddedMetaData()`) be more reliable than reflection on annotation names? | rmannibucau |
| 3683000504 | [3683000504](https://github.com/apache/openjpa/pull/144#discussion_r3683000504) | Direct access to ImplHelper._unenhancedInstanceMap | **(low)** Reaching into `ImplHelper._unenhancedInstanceMap` (a public mutable static field) directly is fragile - suggest a small `ImplHelper.registerUnenhancedInstance(obj, pc)` method instead of exposing the raw map. | rmannibucau |
| 3683001426 | [3683001426](https://github.com/apache/openjpa/pull/144#discussion_r3683001426) | dropExcludedTypeTables drops user tables with raw SQL | **(high)** `dropExcludedTypeTables` issues a raw `"DROP TABLE " + tableName` bypassing the dictionary (no identifier quoting/`toDBName`, no CASCADE handling, will fail on Postgres with dependent constraints) and swallows every exception at trace level. More fundamentally, dropping a user table because its type was excluded from synchronization is destructive - an excluded type may be a table managed externally on purpose. Is this only here to make a specific test pass? It probably should not ship in production code. | rmannibucau |
| 3683001538 | [3683001538](https://github.com/apache/openjpa/pull/144#discussion_r3683001538) | NULLS FIRST/LAST string rewrite breaks on commas, triplicated | **(high)** The NULLS FIRST/LAST emulation finds the last order term with `sql.lastIndexOf(", ", termDirStart)`, so any ORDER BY expression containing a comma (e.g. `COALESCE(t0.x, 0) DESC`) is split mid-argument-list and the rewrite produces corrupt SQL; duplicating the expression also duplicates `?` markers without duplicating bound parameters. The block is triplicated in MariaDBDictionary (~575) and SQLServerDictionary (~484) - can it be extracted to a shared helper operating on the order term before it is appended to the buffer instead of string-parsing it back out? | rmannibucau |
| 3683001854 | [3683001854](https://github.com/apache/openjpa/pull/144#discussion_r3683001854) | TREAT discriminator filter excludes subclasses of target | **(medium)** `appendTreatDiscriminator` emits `disc = <treated class value>` only. Per JPA, `TREAT(x AS Middle)` must also match subtypes of Middle, so for a 3-level hierarchy this incorrectly filters out instances of Middle's subclasses - it should be an IN over the discriminator values of the treated class and all mapped subclasses. It also only handles `cols[0]` of the discriminator. | rmannibucau |
| 3683001994 | [3683001994](https://github.com/apache/openjpa/pull/144#discussion_r3683001994) | Schema-gen methods leak a Broker just to get classloader | **(medium)** `createPersistenceStructure`, `dropPersistenceStrucuture`, `validatePersistenceStruture` and `truncateData` each create a Broker via `super.newBrokerImpl(...)` that is only used for `getClassLoader()` and never closed - a broker (and its resources) leaked per call. Can the classloader be obtained without instantiating a broker? | rmannibucau |
| 3683002126 | [3683002126](https://github.com/apache/openjpa/pull/144#discussion_r3683002126) | Static _droppedTables shared across concurrent EMFs | **(medium)** `_droppedTables` is JVM-global static mutable state and `clearDroppedTables()` is invoked from JDBCBrokerFactory whenever any EMF with schema-gen properties spins up - with two persistence units initializing concurrently (common in app servers) one EMF wipes the other's in-flight tracking. Matching also uses `toUpperCase()` without `Locale.ROOT` (here, line 1239 and 1519-1529) and compares a full identifier against a name regex-stripped from raw DDL, so schema-qualified or quoted names will not match. Could this state live on the configuration instead? | rmannibucau |
| 3683002267 | [3683002267](https://github.com/apache/openjpa/pull/144#discussion_r3683002267) | Range ignored in executeSetOperatorQuery | **(medium)** `executeSetOperatorQuery` receives `range` but never uses it, so `setFirstResult`/`setMaxResults` on a UNION/INTERSECT/EXCEPT query are silently ignored. Should the range at least be applied via RangeResultObjectProvider like the normal path does? | rmannibucau |
| 3683002420 | [3683002420](https://github.com/apache/openjpa/pull/144#discussion_r3683002420) | Bulk delete no longer cleans dependent/collection rows | **(medium)** Removing the `getCascadeDelete() != CASCADE_NONE -> INVALID` guard means bulk DELETE no longer falls back to loading instances for entities with cascading/dependent fields. JPA 4.10 (no cascade on bulk delete) is fine, but this strategy also handled dependent-field cleanup: join-table / element-collection rows previously removed via the in-memory fallback can now be left orphaned unless the DB has ON DELETE CASCADE. Was that trade-off verified for the element-collection case? | rmannibucau |
| 3683002577 | [3683002577](https://github.com/apache/openjpa/pull/144#discussion_r3683002577) | Long cast uses decimalTypeName instead of bigint | **(medium)** Casting to Long uses `dict.decimalTypeName`; on MySQL `CAST(x AS DECIMAL)` defaults to DECIMAL(10,0), so large long values overflow/truncate - why not `bigintTypeName` for the long case? Also `getDbNumberTargetTypeName` sanitizes the `{0}` size suffix while the sibling TypecastAsString.java:152 appends `dict.varcharTypeName` raw - the two siblings should share the same sanitize logic. | rmannibucau |
| 3683002730 | [3683002730](https://github.com/apache/openjpa/pull/144#discussion_r3683002730) | VersionVal NPEs on surrogate or missing version | **(medium)** `getColumns()` NPEs when the entity has a surrogate version or no version at all (`getVersionFieldMapping()` returns null), so `VERSION(e)` on such an entity dies with NullPointerException instead of a meaningful error - `initialize` should validate this like it validates the class mapping. The error at line 99 also reuses the `bad-getobjectid` message, which is misleading for a VERSION() failure. | rmannibucau |
| 3683003006 | [3683003006](https://github.com/apache/openjpa/pull/144#discussion_r3683003006) | IdClass paths swallow exceptions and rely on field order | **(medium)** The IdClass reconstruction/extraction paths `catch (Exception)` and silently continue (here the field stays null; in `toDataStoreValue` at line 227 the PK columns get nulls written). Swallowing exceptions around primary-key values risks silently persisting/loading corrupt identities - at minimum a warn log, arguably a StoreException. Also `getInstanceFields` (line 448) maps IdClass fields to columns by `getDeclaredFields()` order, which the JVM does not guarantee - matching by name would be safer. | rmannibucau |
| 3683003132 | [3683003132](https://github.com/apache/openjpa/pull/144#discussion_r3683003132) | Instant.now() precision loss on DB round-trip | **(medium)** `Instant.now()` carries micro/nano precision on modern JVMs; if the version column's precision is lower (MySQL TIMESTAMP defaults, Oracle DATE) the value read back differs from the in-memory version, producing spurious optimistic-lock failures on the next flush - the same reason TimestampVersionStrategy deliberately uses millisecond granularity. Should this truncate to a precision known to survive the DB round-trip? | rmannibucau |
| 3683003222 | [3683003222](https://github.com/apache/openjpa/pull/144#discussion_r3683003222) | Null named parameter falls through to positional lookup | **(medium)** Using `userParams.get(name) == null` to fall through to positional lookup means an explicitly bound null named parameter is silently replaced by whatever is registered under the position key - `containsKey` should distinguish "bound to null" from "absent". Related: the new `c.getIndex() < params.length` guards at lines 188/195 silently skip binding instead of failing, turning a caller bug into an unbound-parameter SQLException far from the cause. | rmannibucau |
| 3683003316 | [3683003316](https://github.com/apache/openjpa/pull/144#discussion_r3683003316) | storeCharsAsNumbers default flip breaks existing schemas | **(medium)** Flipping `storeCharsAsNumbers` to false for PostgreSQL >= 9 changes the default mapping for existing applications: char fields previously stored in INTEGER columns will now map/validate as CHAR, so schemas created by older OpenJPA versions fail validation or read wrongly after an upgrade. Intended compatibility break? Should be release-noted and overridable. | rmannibucau |
| 3683003416 | [3683003416](https://github.com/apache/openjpa/pull/144#discussion_r3683003416) | Ceiling mutates shared operator field in appendTo | **(low)** `appendTo` mutates the instance field `operator` before delegating to `super.appendTo` (same pattern in NaturalLogarithm.java:49). Compiled query plans are cached and shared, so this is a data race on shared state; passing the dictionary function down locally (e.g. an `appendTo(..., String operator)` overload in UnaryOp) would keep the Val immutable. | rmannibucau |
| 3683003654 | [3683003654](https://github.com/apache/openjpa/pull/144#discussion_r3683003654) | Converter instantiated reflectively, skips CDI and nulls | **(low)** Two questions: (1) the converter is instantiated via `getDeclaredConstructor().newInstance()`, bypassing CDI-managed converters (JPA allows converters as CDI beans with injection); (2) why reflection/`findMethod` instead of casting to `jakarta.persistence.AttributeConverter` and calling it directly? Note also the `val == null` short-circuits mean a converter mapping null to a default value is never consulted for nulls. | rmannibucau |
| 3683004301 | [3683004301](https://github.com/apache/openjpa/pull/144#discussion_r3683004301) | String cache mode properties no longer converted to enum | **(medium)** The early `return (T) value;` now also fires for String values of `cache.retrieveMode`/`cache.storeMode`, skipping the enum conversion below. Since EntityManagerImpl now exposes `setCacheRetrieveMode(CacheRetrieveMode)`, `em.setProperty("jakarta.persistence.cache.retrieveMode", "USE")` will try to inject a raw String into the enum setter and fail, whereas the old code converted it. Should Strings still be converted to the target enum here? | rmannibucau |
| 3683004426 | [3683004426](https://github.com/apache/openjpa/pull/144#discussion_r3683004426) | treat() join overloads silently cast without narrowing | **(medium)** Only `treat(Root)` gets a real implementation (`RootImpl.TreatedRoot`); all the join overloads (lines 429-450) and `treat(Path)` (line 458) just cast and return the same object. That is a silent no-op: no type narrowing is applied, but instead of the previous explicit UnsupportedOperationException users now get wrong behavior with no diagnostic. Could the unsupported overloads keep throwing (or get a TreatedJoin analogous to TreatedRoot)? | rmannibucau |
| 3683004555 | [3683004555](https://github.com/apache/openjpa/pull/144#discussion_r3683004555) | version 3.1 persistence.xml validated against 3.0 XSD | **(medium)** Documents declaring `version="3.1"` are routed to `persistence_3_0.xsd.rsrc`, but that schema declares `version` as `fixed="3.0" use="required"`, so such documents always fail XSD validation - and with the new SAX-rethrow logic at line 570 this now aborts unit discovery instead of being skipped. Is the branch intentional, and should not it validate against a schema that accepts "3.1"? (Note the copy-pasted `PERSISTENCE_XSD_3_0` in the 3.1 condition.) | rmannibucau |
| 3683004644 | [3683004644](https://github.com/apache/openjpa/pull/144#discussion_r3683004644) | convert() mutates caller config, ignores mappingFiles | **(medium)** `convert(PersistenceConfiguration)` mutates the caller's configuration object (`config.property(...)` for MetaDataFactory and noPersistenceXMLResource) - a surprising side effect for a converter, and repeated `createEntityManagerFactory(config)` calls keep appending. It also ignores `config.mappingFiles()` and `config.qualifiers()` entirely, and `setPersistenceUnitName(config.name())` is called twice (lines 648 and 662). Could the OpenJPA-specific properties go into the returned map instead, and mapping files be wired through? | rmannibucau |
| 3683004763 | [3683004763](https://github.com/apache/openjpa/pull/144#discussion_r3683004763) | Typos, stray semicolon, and validate() masking unsupported | **(medium)** Nits before this freezes: the delegated `BrokerFactory` method names carry the `Strucuture`/`Struture` typos, `truncateData();;` has a double semicolon at line 64, and the `(Exception) ex` cast at line 58 is redundant. Also `validate()` wraps even UnsupportedOperationException from stores that do not implement validation into `SchemaValidationException("Schema could not be validated: null")`, misreporting a missing capability as a validation failure. | rmannibucau |
| 3683004886 | [3683004886](https://github.com/apache/openjpa/pull/144#discussion_r3683004886) | getReference(entity) fails on composite ids | **(medium)** `getReference(T entity)` only extracts the PK when `pkFields.length == 1`; for composite/IdClass/EmbeddedId entities `pk` stays null and the call fails downstream with a misleading "null pk" IllegalArgumentException. Also `entity.getClass()` (line 2657) may be a runtime subclass without direct metadata. Could composite ids be supported via `broker.getObjectId`, or at least fail with an explicit "composite id not supported" message? | rmannibucau |
| 3683005009 | [3683005009](https://github.com/apache/openjpa/pull/144#discussion_r3683005009) | addNamedQuery relabels criteria query as JPQL | **(medium)** `addNamedQuery` re-labels a criteria query as JPQL using `queryImpl.getQueryString()`, which for criteria queries is the CQL/toString rendering - OpenJPA has never guaranteed that string is parseable JPQL (parameter rendering, literals, treated paths). Has this been exercised beyond simple queries? The three `catch (Exception) { // ignore }` blocks below (lines 512-540) would also hide genuine failures - they could be narrowed to IllegalStateException where the spec defines it. | rmannibucau |
| 3683005121 | [3683005121](https://github.com/apache/openjpa/pull/144#discussion_r3683005121) | Dead access-type annotation helper methods | **(medium)** `hasMixedAnnotations`, `hasFieldStrategyAnnotations` (547) and `hasGetterStrategyAnnotations` (556) are never called from anywhere - dead code from an earlier iteration of the access-type rework; suggest removing. | rmannibucau |
| 3683005250 | [3683005250](https://github.com/apache/openjpa/pull/144#discussion_r3683005250) | getProperties() caches map missing EM-level defaults | **(low)** The old else branch seeding `getProperties()` from a throwaway EM was removed, so the result now depends on whether an EM was created before the first call - and since the map is cached, the EM-level defaults are then permanently missing. Intentional, or should the cache be invalidated once `emEmptyPropsProperties` becomes available? | rmannibucau |
| 3683005413 | [3683005413](https://github.com/apache/openjpa/pull/144#discussion_r3683005413) | Locale-sensitive toUpperCase on temporal field name | **(low)** `field.toString().toUpperCase()` is locale-sensitive ("minute" breaks under a Turkish default locale). Prefer `toUpperCase(Locale.ROOT)`, and ideally key off the known LocalDateField/LocalTimeField constants rather than `toString()`. | rmannibucau |
| 3683005700 | [3683005700](https://github.com/apache/openjpa/pull/144#discussion_r3683005700) | Dropped non-Serializable IdClass warning | **(low)** The "IdClass does not implement Serializable" warning was silently dropped both here and in AnnotationPersistenceMetaDataParser. Deliberate (3.2 relaxes it?) or lost in the rewrite? | rmannibucau |
| 3683005795 | [3683005795](https://github.com/apache/openjpa/pull/144#discussion_r3683005795) | Mandatory JPA 3.2 methods throw UnsupportedOperationException | **(low)** `getNamedQueries(Class)` still throws UnsupportedOperationException, as do `EntityManagerImpl.createQuery(TypedQueryReference)` (EntityManagerImpl.java:2779) and `find(EntityGraph, Object, FindOption...)` (EntityManagerImpl.java:2645). These are mandatory JPA 3.2 API - planned before merge, or tracked in a follow-up JIRA? Worth referencing the issue in the exception message. | rmannibucau |
| 3683006065 | [3683006065](https://github.com/apache/openjpa/pull/144#discussion_r3683006065) | setTimeout(null) cannot clear a previously set query timeout | **(low)** `setTimeout(null)` is silently ignored, so once a timeout is set it can never be cleared through this API (and `getTimeout()` keeps returning the stale value). Should null reset the fetch plan's query timeout to its default? | rmannibucau |
| 3683006222 | [3683006222](https://github.com/apache/openjpa/pull/144#discussion_r3683006222) | Externalized-parameter tests reduced to no-op assertions | **(high)** These three tests kept their names ("CanDetectExternalized...") but no longer detect anything: the `getExpressions()` helper was deleted and the `isUsingExternalizedParameter(...)` assertions were replaced by `assertNotNull(getResultList())`, which can never fail. Was externalized-parameter detection actually removed from the prepared-query cache, or can the original assertions be restored? As written the tests are no-ops. | rmannibucau |
| 3683006359 | [3683006359](https://github.com/apache/openjpa/pull/144#discussion_r3683006359) | LOCAL TIME test query is a tautology matching all rows | **(high)** The query in testGetCurrentLocalTime was changed to `localTimeField < LOCAL TIME OR localTimeField >= LOCAL TIME`, a tautology matching every row no matter what LOCAL TIME evaluates to. The test now only verifies the query parses. Could we keep an assertion that actually constrains the result (e.g. compare against a value persisted just before)? | rmannibucau |
| 3683006506 | [3683006506](https://github.com/apache/openjpa/pull/144#discussion_r3683006506) | Results always materialized, lazy ResultList behavior lost | **(high)** Several assertions here (and in TestQueryTimeout) were inverted from "iterator must be invalid after query/EM close" to "iterator still works because results are now an ArrayList snapshot". Which JPA 3.2 clause requires this? More importantly, does this mean the lazy ResultList (openjpa.FetchBatchSize streaming results) is gone and results are always fully materialized? That would be a significant memory/perf behavior change deserving explicit discussion and release-noting, not just adjusted tests. | rmannibucau |
| 3683006632 | [3683006632](https://github.com/apache/openjpa/pull/144#discussion_r3683006632) | Bulk delete no longer cleans join-table rows | **(high)** testSingleDelete/testBulkDelete were inverted from "addresses deleted" to "addresses remain" citing spec 4.10 - but that clause has said bulk delete does not cascade since JPA 1.0, so this is a deliberate break with long-standing OpenJPA behavior rather than something new in 3.2. Also the `assertSQL("DELETE FROM .*J_PERSON_ADDRESSES .*")` assertions were dropped entirely: are the join-table rows still cleaned up, or do we now leave dangling rows pointing at deleted pks (FK violation on constrained schemas)? Please keep an assertion on the join-table state and consider a compatibility option plus release note. Same change in TestBulkJPQLAndDataCache.java:122. | rmannibucau |
| 3683006744 | [3683006744](https://github.com/apache/openjpa/pull/144#discussion_r3683006744) | Deeply nested multiselect extension now rejected | **(medium)** testDeeplyNestedShape previously verified OpenJPA's documented extension supporting arbitrary nesting of tuple/array selections (the old comment even said the negative test was retired for that reason); it is now inverted to expect IllegalArgumentException. The spec's "must not" has been there since 2.0, so this drops a working extension existing applications may rely on. Intentional, and should it be release-noted? | rmannibucau |
| 3683006891 | [3683006891](https://github.com/apache/openjpa/pull/144#discussion_r3683006891) | Non-entity classes in persistence.xml silently skipped | **(medium)** Inverted from "listing a non-persistent class in persistence.xml raises ArgumentException" to "non-entity classes are silently skipped". Silent skipping also hides real user errors (forgotten annotations, broken enhancement) that previously failed fast. Is this required by a specific TCK test? If so, could we at least keep a warning log and reference the TCK requirement in a comment? | rmannibucau |
| 3683007048 | [3683007048](https://github.com/apache/openjpa/pull/144#discussion_r3683007048) | Renamed getaXxx accessors drop JavaBeans naming coverage | **(medium)** The accessors were renamed from the JavaBeans-Introspector style (getaCAPITAL/getaWord/isaBoolean for fields aCAPITAL/aWord/aBoolean) to getACAPITAL/getAWord/isABoolean. This test existed precisely to cover the former naming, so property-access entities using IDE-generated getaXxx accessors would silently stop being recognized. Did 3.2 change property-name resolution, or is this adapting the test to a regression? Could both variants stay covered? | rmannibucau |
| 3683007155 | [3683007155](https://github.com/apache/openjpa/pull/144#discussion_r3683007155) | Map-key column default KEY0 to entityCs_KEY breaks upgrades | **(medium)** Changing the expected default map-key column from KEY/KEY0 to entityCs_KEY (also TestContainerSpecCompatibilityOptions.java:426 and the KEY0 -> photos_KEY expected SQL in TestTypesafeCriteria) is spec-correct, but silently changes DDL/SQL against existing schemas created by older OpenJPA versions - upgrades will not find the KEY0 column. Should this be gated behind a compatibility option (this test class exists exactly for that) and called out in migration notes? | rmannibucau |
| 3683007396 | [3683007396](https://github.com/apache/openjpa/pull/144#discussion_r3683007396) | assertSQL now ignores identifier delimiters suite-wide | **(medium)** assertSQL() now also matches after stripping identifier delimiters (same idea as the new same() helper in AbstractCriteriaTestCase.java:159). This globally relaxes every SQL assertion in the suite and would mask regressions in delimited-identifier handling. Could the delimiter-insensitive comparison be opt-in, or at least documented why it became necessary? | rmannibucau |
| 3683007607 | [3683007607](https://github.com/apache/openjpa/pull/144#discussion_r3683007607) | testNotLoadedLazy duplicates eager check, lazy path untested | **(low)** In this rewrite, testNotLoadedLazy still calls `verifyIsLoadedEagerState(false)` (duplicate of testNotLoadedEager), so the lazy not-loaded path (`verifyIsLoadedLazyState(false)`) remains untested. Also createLazyEntity builds a RelEntity that is never persisted, which the new testLoadingLazyAttributeByName relies on. | rmannibucau |
| 3683007780 | [3683007780](https://github.com/apache/openjpa/pull/144#discussion_r3683007780) | Deletion of TestSecurityContext needs rationale in PR | **(low)** This is the only deleted test file; deletion looks justified (SecurityManager removal on modern JDKs), but please state the rationale in the PR description so the removal is clearly intentional. | rmannibucau |
| 3683007909 | [3683007909](https://github.com/apache/openjpa/pull/144#discussion_r3683007909) | MariaDB branch accepts either message without naming versions | **(low)** The MariaDB branch now accepts either the per-row or first-row failed object/message "across versions", weakening the exact-match check still applied to other DBs. If specific MariaDB versions differ, could the comment name the versions observed so this does not quietly absorb future regressions? | rmannibucau |
| 3683008653 | [3683008653](https://github.com/apache/openjpa/pull/144#discussion_r3683008653) | Leftover [2024] bracket and stale CDDL sentence vs EFSL 1.1 | **(medium)** Two nits: the template brackets survived in "Copyright (c) [2024] Eclipse Foundation AISBL", and the next paragraph still says "OpenJPA elects to include this software in this distribution under the CDDL license" while the surrounding text was changed to EFSL 1.1 - should the CDDL sentence be updated for consistency? | rmannibucau |
| 3683008798 | [3683008798](https://github.com/apache/openjpa/pull/144#discussion_r3683008798) | Oracle profile bind-mount jdbc_oradata outside the checkout | **(medium)** The oracle profile bind-mounts `${project.basedir}/../jdbc_oradata`, which for the root pom resolves outside the checkout (and to a different path per module since profiles are inherited); run-build-matrix.sh then pre-creates it with `chmod a+rwx` and warns that cleanup needs sudo. Would a named docker volume (or a path under `target/`) be cleaner so nothing leaks outside the repo? | rmannibucau |
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3810111772
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypesafeCriteria.java:
##########
@@ -1781,5 +1789,168 @@ public void testIdClass() {
assertEquivalence(cq, jpql);
}
+
+ public void testLeft() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where left(p.name, 4) = 'John'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.left(c.get("name"), 4), "John"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testRight() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where RIGHT(p.name, 3) = 'Doe'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.right(c.get("name"), 3), "Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testReplace() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ String jpql = "select p from Person p where REPLACE(p.name, 'ohn', 'ack') = 'Jack Fitzgerald Doe'";
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.replace(c.get("name"), "ohn", "ack"), "Jack Fitzgerald Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ /**
+ * JPA 3.2 Criteria UNION must execute end-to-end and produce the
+ * same SQL as the JPQL UNION form. We don't compare row counts
+ * because TestTypesafeCriteria shares a static EMF with other test
+ * classes and we don't want to seed shared tables.
+ */
+ public void testCriteriaUnion() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 30));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.equal(r2.get("name"), "Ugo"));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> union = cb.union(q1, q2);
+ assertNotNull(em.createQuery(union).getResultList());
+ }
+
+ public void testCriteriaUnionAll() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 25));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.gt(r2.<Integer>get("age"), 30));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> unionAll = cb.unionAll(q1, q2);
+ assertNotNull(em.createQuery(unionAll).getResultList());
+ }
+
+ public void testCriteriaExcept() {
Review Comment:
I would appreciate if you can review this abec04bcc commit :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3809672607
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypesafeCriteria.java:
##########
@@ -1781,5 +1789,168 @@ public void testIdClass() {
assertEquivalence(cq, jpql);
}
+
+ public void testLeft() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where left(p.name, 4) = 'John'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.left(c.get("name"), 4), "John"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testRight() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where RIGHT(p.name, 3) = 'Doe'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.right(c.get("name"), 3), "Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testReplace() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ String jpql = "select p from Person p where REPLACE(p.name, 'ohn', 'ack') = 'Jack Fitzgerald Doe'";
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.replace(c.get("name"), "ohn", "ack"), "Jack Fitzgerald Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ /**
+ * JPA 3.2 Criteria UNION must execute end-to-end and produce the
+ * same SQL as the JPQL UNION form. We don't compare row counts
+ * because TestTypesafeCriteria shares a static EMF with other test
+ * classes and we don't want to seed shared tables.
+ */
+ public void testCriteriaUnion() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 30));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.equal(r2.get("name"), "Ugo"));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> union = cb.union(q1, q2);
+ assertNotNull(em.createQuery(union).getResultList());
+ }
+
+ public void testCriteriaUnionAll() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 25));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.gt(r2.<Integer>get("age"), 30));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> unionAll = cb.unionAll(q1, q2);
+ assertNotNull(em.createQuery(unionAll).getResultList());
+ }
+
+ public void testCriteriaExcept() {
Review Comment:
Maybe `Configuration`/`OpenJPAConfiguration` can be extended to have something we can use (for. ex. `DBType`) ?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3812621103
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestTimeoutException.java:
##########
@@ -97,6 +99,37 @@ public void testQueryTimeOutExceptionWhileQueryingWithLocksOnAlreadyLockedEntiti
}
}
+ public void testLockTimeOutExceptionWhileQueryingWithLocksOnAlreadyLockedEntitiesOption() {
Review Comment:
I 'd like to, but it's something we should deal after this release, don't you think?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3812627140
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestTimeoutException.java:
##########
@@ -97,6 +99,37 @@ public void testQueryTimeOutExceptionWhileQueryingWithLocksOnAlreadyLockedEntiti
}
}
+ public void testLockTimeOutExceptionWhileQueryingWithLocksOnAlreadyLockedEntitiesOption() {
Review Comment:
> I 'd like to, but it's something we should deal after this release, don't you think?
+1
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rmannibucau (via GitHub)" <gi...@apache.org>.
rmannibucau commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3426789899
##########
.github/dependabot.yml:
##########
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+version: 2
Review Comment:
not sure we do all agree on that, can be worth a list discussion and separate pr, no?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rmannibucau (via GitHub)" <gi...@apache.org>.
rmannibucau commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3426812145
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedStatementManagerImpl.java:
##########
@@ -120,14 +120,21 @@ protected void flushAndUpdate(RowImpl row)
try {
int count = executeUpdate(stmnt, sql, row);
if (count != 1) {
- logSQLWarnings(stmnt);
- Object failed = row.getFailedObject();
- if (failed != null)
- _exceptions.add(new OptimisticException(failed));
- else if (row.getAction() == Row.ACTION_INSERT)
- throw new SQLException(_loc.get(
- "update-failed-no-failed-obj", String.valueOf(count),
- sql).getMessage());
+ // For DELETE actions, tolerate count=0 because the row may
+ // have already been removed by a database-level ON DELETE
+ // CASCADE triggered by a related row's deletion.
+ if (count == 0 && row.getAction() == Row.ACTION_DELETE) {
Review Comment:
same, to review if we don't loop a case there
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3588437336
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
I debugged the time stuff also with a small standalone `main()` against an in-memory HSQLDB (`jdbc:hsqldb:mem:x`), creating the column once as `TIME WITH TIME ZONE` (what OpenJPA currently generates for `java.time.OffsetTime` on HSQLDB) and once as plain `TIME`, and inserting the values exactly the way our `DBDictionary` binds them.
The key point is how OpenJPA handles `OffsetTime` in `DBDictionary`: on store, the value is normalized to the JVM default offset and bound as a plain `java.sql.Time` (`val.withOffsetSameInstant(OffsetDateTime.now().getOffset()).toLocalTime()`); on load, a plain `Time` is read and the JVM default offset is re-attached. So the offset that ends up in the database is always the session offset — it carries no real information — and the normalization can wrap the local time past midnight. In your run: `04:57:15-09:00` became `20:57:15+07:00`, but the second value (persisted from `LocalTime.now()` at offset `-09:00`) wrapped to `05:12:34+07:00`.
HSQLDB then does the standard-compliant thing for `TIME WITH TIME ZONE` and computes `MAX`/`MIN` by the UTC instant: `05:12:34+07:00` is `22:12:34Z` while `20:57:15+07:00` is only `13:57:15Z`, so `MAX` returns `05:12:34+07:00` — exactly the "wrong" value from the assertion, and `MIN` returns the mirror image, which is why both are broken at once. My standalone program shows both variations: with a `TIME WITH TIME ZONE` column I get your failure, with a plain `TIME` column I get the expected values. It also explains why the failure depends on the time of day / timezone the test runs in: it only bites when one of the persisted values wraps past midnight during the normalization.
Every other dictionary avoids this by storing a zone-less type for `OffsetTime` (Derby maps `TIME_WITH_TIMEZONE` to `TIME` in `getPreferredType`, SQLServer and older H2 set `timeWithZoneTypeName = "TIME"`), which matches the local-time semantics of our normalize-to-JVM-offset scheme. So I'd do the same for HSQLDB. Maybe something like this works:
```java
// HSQLDictionary
@Override
public int getPreferredType(int type) {
if (type == Types.TIME_WITH_TIMEZONE) {
// HSQLDB compares TIME WITH TIME ZONE values by their UTC instant
// (SQL standard), but OpenJPA normalizes OffsetTime values to the
// JVM default offset on store and load. The stored offset therefore
// carries no information, while the normalization may wrap the local
// time around midnight, so MIN/MAX/ORDER BY on such a column return
// different rows than on other databases. Use a plain TIME column
// instead so comparisons happen on the normalized local time.
return Types.TIME;
}
if (dbMajorVersion > 1) {
return super.getPreferredType(type);
}
// ... existing 1.x handling unchanged
}
```
With that change `TestJava8TimeTypes` passes on `-Ptest-hsqldb` (17/17). To be sure it isn't just passing by luck of the clock, I also ran it with `TZ=Etc/GMT-11`, which deterministically triggers the midnight wrap: without the change it fails with exactly your signature (`expected:<21:55:42+11:00> but was:<00:57:15+11:00>` plus the mirrored `testMinOffsetTime` failure), with the change it is green.
For completeness: binding the `OffsetTime` natively via `setObject` instead would not help here — the aggregate would still be computed on UTC instants and disagree with what the test (and all other supported databases) expect. This also covers the `MIN(...)` case from your follow-up comment.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4989957992
I have tested with `-Ptest-h2`
The first error is in the build logs:
```
[INFO] --- antrun:3.1.0:run (generate-standard-sco-proxies) @ openjpa-kernel ---
11:42:34 [INFO] Executing tasks
11:42:34 [ERROR] [java] java.lang.UnsupportedOperationException: The Security Manager is deprecated and will be removed in a future release
11:42:34 [java] at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:194)
11:42:34 [java] at org.apache.tools.ant.taskdefs.Java.run(Java.java:891)
```
seems to affect nothing
Others:
```
[ERROR] org.apache.openjpa.persistence.detach.TestDetachNoProxy.testClear10Compat -- Time elapsed: 5.898 s <<< FAILURE!
junit.framework.AssertionFailedError: Expected sqlDate endsWith($proxy) to return true
..........
at org.apache.openjpa.persistence.detach.TestDetachNoProxy.verifyEntities(TestDetachNoProxy.java:437)
[ERROR] org.apache.openjpa.persistence.detach.TestDetachNoProxy.testClear20Compat -- Time elapsed: 0.134 s <<< FAILURE!
[ERROR] Tests run: 11, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 44.02 s <<< FAILURE! -- in org.apache.openjpa.persistence.proxy.delayed.tset.TestDelayedTreeSetProxyDetachLite
[ERROR] org.apache.openjpa.persistence.proxy.delayed.tset.TestDelayedTreeSetProxyDetachLite.testProxyMethods -- Time elapsed: 7.413 s <<< FAILURE!
junit.framework.AssertionFailedError:
Expected regular expression
<SELECT .* DC_EMPLOYEE .*
>
to be contained in SQL statements:
SELECT t0.id FROM DC_DEPARTMENT t0 WHERE t0.id = ?
SELECT t0.awdName, t0.awdType FROM DC_DEP_AWD t0 WHERE t0.DEPARTMENT_ID = ?
SELECT t1.id, t1.name FROM DC_DEP_PRD t0 INNER JOIN Product t1 ON t0.PRODUCTS_ID = t1.id WHERE t0.DEPARTMENT_ID = ?
at junit.framework.Assert.fail(Assert.java:57)
at junit.framework.TestCase.fail(TestCase.java:223)
at org.apache.openjpa.persistence.test.SQLListenerTestCase.assertAnySQLAnyOrder(SQLListenerTestCase.java:191)
```
and more with similar stack trace (same result on `master`)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4999711201
I am currently looking into my suggestion regarding Romains comment.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3503077257
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
It seems `MINUS` should be used for `Oracle`: https://stackoverflow.com/questions/5557991/minus-vs-except-difference-in-oracle-sql-server
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3557496341
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
The only issues with MSSQL so far:
```
[ERROR] TestEJBQLFunction>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testExtractTimeFromInstant:688 » Persistence The data types time and datetime are incompatible in the equal to operator. {prepstmnt 1806640599 SELECT t0.userid, t0.DTYPE, t0.version, t1.id, t1.city, t1.country, t1.streetAd, t2.userid, t2.DTYPE, t2.version, t2.age, t2.compName, t2.creditRating, t2.name, t2.nameAsLob, t1.zipcode, t0.age, t0.compName, t0.creditRating, t0.name, t0.nameAsLob FROM CompUser t0 LEFT OUTER JOIN Address t1 ON t0.ADD_ID = t1.id LEFT OUTER JOIN CompUser t2 ON t1.id = t2.ADD_ID WHERE (CAST( {ts '2005-03-21 01:32:21'} AS TIME) = {t '01:32:21'})} [code=402, state=S0001]
[ERROR] TestEJBQLFunction>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testExtractTimeFromLocalTime:712 » Persistence The data types time and datetime are incompatible in the equal to operator. {prepstmnt 1975171943 SELECT t0.userid, t0.DTYPE, t0.version, t1.id, t1.city, t1.country, t1.streetAd, t2.userid, t2.DTYPE, t2.version, t2.age, t2.compName, t2.creditRating, t2.name, t2.nameAsLob, t1.zipcode, t0.age, t0.compName, t0.creditRating, t0.name, t0.nameAsLob FROM CompUser t0 LEFT OUTER JOIN Address t1 ON t0.ADD_ID = t1.id LEFT OUTER JOIN CompUser t2 ON t1.id = t2.ADD_ID WHERE (CAST( CONVERT(TIME, GETDATE()) AS TIME) = {t '01:32:20'})} [code=402, state=S0001]
```
Not sure how can it be fixed :((
Any hints are much appreciated :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3584804182
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
Another issue is:
```
[ERROR] TestJPQLScalarExpressions>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testSimpleCaseExpressions:212 the result is not male expected:<Male> but was:<Male >
```
on this JPQL: https://github.com/apache/openjpa/blob/OPENJPA-2940/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/expressions/TestJPQLScalarExpressions.java#L201
I believe this is because `Male` is right-padded with spaces to match the length of `Female`
I'm going to add comparison using `trim/equalsIgnoreCase`
Would it be OK? :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3689140055
##########
openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java:
##########
@@ -330,4 +332,27 @@ public static Object getManagedInstance(Object o) {
else
return o;
}
+
+ /**
+ * Returns the entity class for the given object, unwrapping any
+ * runtime-generated pcsubclass proxy. For runtime-enhanced entities,
+ * {@code obj.getClass()} returns the generated subclass (e.g.
+ * {@code Order$pcsubclass}), but for {@code equals()}/{@code hashCode()}
+ * comparisons the original entity class should be used.
+ *
+ * @param obj the object whose entity class to determine
+ * @return the original entity class (superclass of pcsubclass), or
+ * the object's actual class if it is not a pcsubclass
+ * @since 4.2.0
+ */
+ public static Class<?> getEntityClass(Object obj) {
+ if (obj == null) {
+ return null;
+ }
+ Class<?> cls = obj.getClass();
+ if (cls.getName().contains("$pcsubclass")) {
Review Comment:
Fixed in 2a8d3831c3092ce10811f496fe045ee7d39ba044: getEntityClass now uses PCEnhancer.isPCSubclassName() (the counterpart of the name generator) and walks superclasses until the name is no longer a generated one, so nested pcsubclasses are unwrapped too. Also extracted the "$pcsubclass" literal into PCEnhancer.PCSUBCLASS_SUFFIX and added a unit test.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3771751937
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java:
##########
@@ -477,7 +823,160 @@ public boolean isLoaded(Object entity, String attribute) {
return (OpenJPAPersistenceUtil.isManagedBy(this, entity) &&
(OpenJPAPersistenceUtil.isLoaded(entity, attribute) == LoadState.LOADED));
}
-
+
+ @Override
+ public <E> boolean isLoaded(E entity, Attribute<? super E, ?> attribute) {
+ return isLoaded(entity, attribute.getName());
+ }
+
+ @Override
+ public SchemaManager getSchemaManager() {
+ if (!this.isOpen()) {
+ throw new IllegalStateException("EntityManagerFactory is closed.");
+ }
+ return new SchemaManagerImpl(_factory);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <R> R callInTransaction(Function<EntityManager, R> work) {
+ EntityManager em = createEntityManager();
+ boolean startedTransaction = false;
+ boolean jtaTransaction = getTransactionType() == PersistenceUnitTransactionType.JTA;
+ Broker broker = em.unwrap(Broker.class);
+ try {
+ if (jtaTransaction) {
+ if (!broker.syncWithManagedTransaction()) {
+ broker.begin();
+ startedTransaction = true;
+ }
+ } else {
+ em.getTransaction().begin();
+ startedTransaction = true;
+ }
+ R result = work.apply(em);
+ if (startedTransaction) {
+ if (jtaTransaction) {
+ broker.commit();
+ } else {
+ em.getTransaction().commit();
+ }
+ }
+ // For unenhanced (runtime-subclassed) entities, the user's function
+ // may return an original POJO that was passed to persist().
+ // Entities loaded via find() on other EMs are subclass instances,
+ // causing getClass() mismatches in equals(). To ensure consistent
+ // class identity, re-find managed entities from the database so that
+ // the returned instance is a subclass (matching what find() returns).
+ if (result != null && em.contains(result)) {
+ try {
+ Object id = getPersistenceUnitUtil().getIdentifier(result);
+ if (id != null) {
+ Class<R> entityClass = (Class<R>) result.getClass();
+ em.clear();
+ R refound = em.find(entityClass, id);
+ if (refound != null) {
+ result = refound;
+ }
+ }
+ } catch (Exception e) {
+ // If re-find fails, return original result
+ }
+ }
+ return result;
+ } catch (Exception ex) {
+ if (jtaTransaction) {
+ broker.rollback();
+ } else {
+ try {
+ em.getTransaction().rollback();
+ } catch (Exception rollbackEx) {
+ // Transaction may already be rolled back
+ }
+ }
+ throw new UserException(ex.getMessage(), ex);
Review Comment:
Changed to throw a PersistenceException.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3780891894
##########
openjpa-integration/tck/run-tck32.sh:
##########
@@ -0,0 +1,210 @@
+#!/bin/bash
+#
+# 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.
+#
+
+TCK_VERSION="${TCK_VERSION:-3.2.0}"
+TCK_BASE="${TCK_VERSION:0:3}"
+
+SCRIPT_ROOT=$(cd -- $(dirname "${0}") && pwd)
+PROJECT_ROOT="$(cd "${SCRIPT_ROOT}/../.." && pwd)"
+
+# derby is removed for now
+# mysql 8.0 is broken! db.delimiter='!' breaks connection
+declare -A FULL_DB_LIST=(
+ [mysql]=mysql
+ [postgresql]=postgresql
+ [mssql]=mssqlserver
+ [oracle]=oracle
+)
+
+declare -A VERSIONS=(
+ [mysql]='8.4.8' # 8.4.8 9.4.0
+ [postgresql]='16'
+)
+
+#
+# Script to download, setup and run the JPA 3.2 TCK against OpenJPA
+# using DB selected.
+#
+# Usage:
+# ./run-tck32.sh # Run full TCK against postgres:16
+# DB_VERSION=18 ./run-tck32.sh # Run full TCK against postgres:18
+# DB_TYPE=mysql ./run-tck32.sh # Run full TCK against mysql:8.4.8
+# DB_HOST=myhost:5432 ./run-tck32.sh # Custom DB host
+# OPENJPA_VERSION=4.2.0-SNAPSHOT ./run-tck32.sh # Custom OpenJPA version
+#
+# Prerequisites:
+# - OpenJPA must be built and installed in local Maven repo
+# (run 'mvn install -DskipTests' from the project root)
+# - Java 17+ and Maven 3.x
+#
+
+set -e
+
+# Check required commands
+MISSING=""
+for cmd in java mvn curl unzip grep sed; do
+ if ! command -v "$cmd" &>/dev/null; then
+ MISSING="${MISSING} - ${cmd}\n"
+ fi
+done
+if [[ -n "$MISSING" ]]; then
+ echo "ERROR: The following required commands are not available:"
+ echo -e "$MISSING"
+ echo "Please install them before running this script."
+ exit 1
+fi
+
+stopAll() {
+ for profile in ${!FULL_DB_LIST[@]}; do
+ echo "Stopping dockerized ${profile}"
+ mvn -N -Ptest-${profile}-docker -f ${PROJECT_ROOT} -Ddocker.stopNamePattern=${profile:0:8}* docker:stop -Ddocker.showLogs
+ done
+}
+
+stopAll
+
+TCK_URL="https://download.eclipse.org/jakartaee/persistence/${TCK_BASE}/jakarta-persistence-tck-${TCK_VERSION}.zip"
+TCK_DIR="${SCRIPT_ROOT}/target/tck32"
+TCK_ZIP="${TCK_DIR}/jakarta-persistence-tck-${TCK_VERSION}.zip"
+TCK_HOME="${TCK_DIR}/persistence-tck"
+OPENJPA_VERSION="${OPENJPA_VERSION:-4.2.0-SNAPSHOT}"
+START_DOCKER=
+
+if [[ -z "${DB_HOST}" ]]; then
+ START_DOCKER=1
+fi
+
+DB_TYPE="${DB_TYPE:-postgresql}"
+DB_HOST="${DB_HOST:-localhost:5555}"
+DB_USER="${DB_USER:-tcktest}"
+DB_PASSWORD="${DB_PASSWORD:-tcktest}"
+DB_NAME="${DB_NAME:-tcktest}"
+DB_URL=""
+declare -a JPROPS=()
+
+DB_HOST_ONLY="${DB_HOST%%:*}"
+DB_PORT="${DB_HOST##*:}"
+
+TCK_DB_TYPE="${FULL_DB_LIST[${DB_TYPE}]}"
+
+setProps() {
+ local ver="${VERSIONS[${DB_TYPE}]}"
+ if [[ -n "${DB_VERSION}" ]]; then
+ ver="${DB_VERSION}"
+ fi
+ if [[ -n "${VERSIONS[${DB_TYPE}]}" ]]; then
+ JPROPS+=("-D${DB_TYPE}.server.version=${ver}")
+ fi
+
+ case ${DB_TYPE} in
+ mysql)
+ DB_URL="jdbc:mysql://${DB_HOST}/${DB_NAME}?useSSL=false&allowPublicKeyRetrieval=true&transformedBitIsBoolean=true"
+ ;;
+ postgresql)
+ DB_URL="jdbc:postgresql://${DB_HOST}/${DB_NAME}"
+ ;;
+ mssql)
+ DB_NAME=""
+ DB_URL="jdbc:sqlserver://${DB_HOST};sendTimeAsDatetime=false;trustServerCertificate=true"
+ ;;
+ oracle)
+ JPROPS+=("-Dopenjpa.oracle.SID=${DB_NAME}")
+ DB_NAME="XE"
+ DB_URL="jdbc:oracle:thin:@${DB_HOST}:${DB_NAME}"
+ ;;
+ esac
+ JPROPS+=("-Ddocker.external.${DB_TYPE}.port=${DB_PORT}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.dbname=${DB_NAME}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.username=${DB_USER}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.password=${DB_PASSWORD}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.url=${DB_URL}")
+}
+
+setProps
+
+if [[ -n "${START_DOCKER}" ]]; then
+ echo "Starting dockerized ${DB_TYPE}"
+ mvn -N -f ${PROJECT_ROOT} -Ptest-${DB_TYPE}-docker "${JPROPS[@]}" docker:start -Ddocker.showLogs
+fi
+
+GF_VERSION="${GF_VERSION:-8.0.0}"
+
+echo "=== JPA ${TCK_BASE} TCK Runner for OpenJPA ==="
+echo "OpenJPA version: ${OPENJPA_VERSION}"
+echo "TCK version: ${TCK_VERSION}"
+echo "GlassFish: ${GF_VERSION}"
+echo "Database: ${DB_TYPE} (${DB_HOST}/${DB_NAME})"
+echo ""
+
+# Step 1: Download TCK if not present
+mkdir -p "${TCK_DIR}"
+if [[ ! -f "${TCK_ZIP}" ]]; then
+ echo "Downloading JPA ${TCK_BASE} TCK..."
+ curl -sL -o "${TCK_ZIP}" "${TCK_URL}"
+ echo "Downloaded."
+else
+ echo "TCK zip already present, skipping download."
+fi
+
+# Step 2: Extract TCK
+if [[ ! -d "${TCK_HOME}" ]]; then
+ echo "Extracting TCK..."
+ cd "${TCK_DIR}" && unzip -q "${TCK_ZIP}"
+ echo "Extracted."
+else
+ echo "TCK already extracted, skipping."
+fi
+
+# Step 3: Install TCK artifacts into local Maven repo
+echo "Installing TCK artifacts..."
+cd "${TCK_HOME}/artifacts" && bash artifact-install.sh "${TCK_VERSION}"
+echo "TCK artifacts installed."
+
+# Step 4: Patch TCK pom.xml to add OpenJPA profile (if not already patched)
+TCK_POM="${TCK_HOME}/bin/pom.xml"
+if [[ -z "$(grep '<id>openjpa</id>' "${TCK_POM}")" ]]; then
+ echo "Adding OpenJPA profile to TCK pom.xml..."
+
+ sed '/<\/profiles>/,$d' "${TCK_POM}" > temp
+ cat "${SCRIPT_ROOT}/tck32-openjpa-profile.xml" >> temp
+ sed '/<\/profiles>/,$!d' "${TCK_POM}" >> temp
+ mv temp "${TCK_POM}"
+
+ echo "OpenJPA profile added."
+else
+ echo "OpenJPA profile already present in TCK pom.xml."
+fi
+
+echo ""
+echo "=== Preparing ${DB_TYPE} database ==="
Review Comment:
corrected
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3780886396
##########
openjpa-integration/tck/run-tck32.sh:
##########
@@ -0,0 +1,210 @@
+#!/bin/bash
+#
+# 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.
+#
+
+TCK_VERSION="${TCK_VERSION:-3.2.0}"
+TCK_BASE="${TCK_VERSION:0:3}"
+
+SCRIPT_ROOT=$(cd -- $(dirname "${0}") && pwd)
+PROJECT_ROOT="$(cd "${SCRIPT_ROOT}/../.." && pwd)"
+
+# derby is removed for now
+# mysql 8.0 is broken! db.delimiter='!' breaks connection
+declare -A FULL_DB_LIST=(
+ [mysql]=mysql
+ [postgresql]=postgresql
+ [mssql]=mssqlserver
+ [oracle]=oracle
+)
+
+declare -A VERSIONS=(
+ [mysql]='8.4.8' # 8.4.8 9.4.0
+ [postgresql]='16'
+)
+
+#
+# Script to download, setup and run the JPA 3.2 TCK against OpenJPA
+# using DB selected.
+#
+# Usage:
+# ./run-tck32.sh # Run full TCK against postgres:16
+# DB_VERSION=18 ./run-tck32.sh # Run full TCK against postgres:18
+# DB_TYPE=mysql ./run-tck32.sh # Run full TCK against mysql:8.4.8
+# DB_HOST=myhost:5432 ./run-tck32.sh # Custom DB host
+# OPENJPA_VERSION=4.2.0-SNAPSHOT ./run-tck32.sh # Custom OpenJPA version
+#
+# Prerequisites:
+# - OpenJPA must be built and installed in local Maven repo
+# (run 'mvn install -DskipTests' from the project root)
+# - Java 17+ and Maven 3.x
+#
+
+set -e
+
+# Check required commands
+MISSING=""
+for cmd in java mvn curl unzip grep sed; do
+ if ! command -v "$cmd" &>/dev/null; then
+ MISSING="${MISSING} - ${cmd}\n"
+ fi
+done
+if [[ -n "$MISSING" ]]; then
+ echo "ERROR: The following required commands are not available:"
+ echo -e "$MISSING"
+ echo "Please install them before running this script."
+ exit 1
+fi
+
+stopAll() {
Review Comment:
`stopAll` moved to command-line option
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4477420919
nope :(
I'll try to compare your script with what we have already :)
Thanks for the pointer
`~800` files changed ... tests are the only hope :))
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3793575195
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
Review Comment:
Just have checked with additional `<user>...</user>` parameter in `pom.xml`
The most straightforward (available out-of-the-box:
`<user>${user.name}</user>`
```
[INFO] --- docker:0.48.1:start (default-cli) @ openjpa-parent ---
[INFO] DOCKER> [container-registry.oracle.com/database/express:18.4.0-xe]: Start container 6b890d23ec2d
[ERROR] DOCKER> Error occurred during container startup, shutting down...
[ERROR] DOCKER> I/O Error [Unable to start container id [6b890d23ec2d] : {"message":"unable to find user solomax: no matching entries in passwd file"} (Internal Server Error: 500)]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
```
with uid manually entered (will require some sort of maven "magic")
`<user>1000</user>`
```
[INFO] --- docker:0.48.1:start (default-cli) @ openjpa-parent ---
[INFO] DOCKER> [container-registry.oracle.com/database/express:18.4.0-xe]: Start container 4fa1a4028c57
4fa1a4> ORACLE_HOME = [/home/oracle] ? ORACLE_BASE environment variable is not being set since this
4fa1a4> information is not available for the current user ID .
4fa1a4> You can set ORACLE_BASE manually if it is required.
4fa1a4> Resetting ORACLE_BASE to its previous value or ORACLE_HOME
4fa1a4> The Oracle base remains unchanged with value /opt/oracle
4fa1a4> #####################################
4fa1a4> ########### E R R O R ###############
4fa1a4> DATABASE SETUP WAS NOT SUCCESSFUL!
4fa1a4> Please check output for further info!
4fa1a4> ########### E R R O R ###############
4fa1a4> #####################################
4fa1a4> The following output is now a tail of the alert.log:
4fa1a4> tail: cannot open '/opt/oracle/diag/rdbms/*/*/trace/alert*.log' for reading: No such file or directory
4fa1a4> tail: no files remaining
[ERROR] DOCKER> [container-registry.oracle.com/database/express:18.4.0-xe]: Container stopped with exit code 1 unexpectedly after 504 ms while waiting on log out 'DATABASE IS READY TO USE'
[ERROR] DOCKER> Error occurred during container startup, shutting down...
[INFO] DOCKER> [container-registry.oracle.com/database/express:18.4.0-xe]: Stop and removed container 4fa1a4028c57 after 0 ms
[ERROR] DOCKER> I/O Error [[container-registry.oracle.com/database/express:18.4.0-xe]: Container stopped with exit code 1 unexpectedly after 504 ms while waiting on log out 'DATABASE IS READY TO USE']
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
```
So, I'm afraid, not much can be done here :(
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801007789
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/InstantVersionStrategy.java:
##########
@@ -0,0 +1,64 @@
+/*
+ * 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.meta.strats;
+
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.meta.JavaTypes;
+
+/**
+ * Uses an {@link Instant} for optimistic versioning.
+ *
+ * @since 4.2.0
+ */
+public class InstantVersionStrategy
+ extends ColumnVersionStrategy {
+
+ private static final long serialVersionUID = 1L;
+ public static final String ALIAS = "version-instant";
+
+ @Override
+ public String getAlias() {
+ return ALIAS;
+ }
+
+ @Override
+ protected int getJavaType() {
+ return JavaTypes.INSTANT;
+ }
+
+ @Override
+ protected Object nextVersion(Object version) {
+ return Instant.now();
+ }
+
+ @Override
+ public Map<Column, String> getBulkUpdateValues() {
+ Column[] cols = vers.getColumns();
+ Map<Column, String> map = new HashMap<>(cols.length);
+ Object d = nextVersion(null);
+ for (Column col : cols) {
+ map.put(col, d.toString());
Review Comment:
should be fixed
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5325797535
> All,
>
> There are lot's of unaddressed comments, but I'm afraid working on them in this PR is a pain :(
>
> Maybe it worth to merge this one and address remaining in a separate PR?
>
> Shall this one be squashed WDYT?
I think people opted for not squashing to remain history. I am fine with merging, but we need a way to track the open stuff to avoid loosing it on the long run.
Perhaps it would make sense to create JIRAs for the open things we need to fix ?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3802486738
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EnumValueHandler.java:
##########
@@ -116,8 +219,26 @@ public Object toDataStoreValue(ValueMapping vm, Object val, JDBCStore store) {
public Object toObjectValue(ValueMapping vm, Object val) {
if (val == null)
return null;
- if (_ordinal)
- return _vals[((Number) val).intValue()];
- return Enum.valueOf(vm.getType(), (String) val);
+ if (_useEnumeratedValue) {
+ initEnumeratedValueField(vm.getType());
+ Enum<?> result = _dbToEnum.get(val);
+ if (result == null && val instanceof Number) {
+ result = _dbToEnum.get(((Number) val).intValue());
+ }
+ if (result == null) {
+ result = _dbToEnum.get(val.toString());
+ }
+ return result;
Review Comment:
> Additionally I wonder why `ENUMERATED_VALUE_CLASS` inited with function call? `EnumeratedValue.class` looks easier
It would be, but it doesn't compile here: `openjpa-jdbc` has no dependency on `jakarta.persistence-api`, and it doesn't get one transitively either (`openjpa-jdbc` → `openjpa-kernel` → `openjpa-lib`, none of them pull it). Only `openjpa-persistence` declares it. There are currently zero `import jakarta.persistence.*` statements in `openjpa-jdbc/src/main/java`, and I'd rather not make this ticket the one that introduces the JPA API as a compile dependency of the JDBC layer.
Moving the detection up into the persistence module doesn't work either, because one of the two callers — `MappingDefaultsImpl#getStrategy` — is itself in `openjpa-jdbc`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3802267514
##########
.github/workflows/ci.yml:
##########
@@ -14,26 +14,37 @@
# specific language governing permissions and limitations under the License.
#
name: Java CI
-on: [push]
+on:
+ push:
+ branches: [master]
Review Comment:
done! :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3414912590
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -107,6 +109,11 @@ public void testTruncate() {
@Test
public void testValidate() {
EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ DBDictionary dict = getDbDictionary(emf);
+ if (dict instanceof MySQLDictionary) {
Review Comment:
Thanks for clarifications
I'll try to reproduce and investigate
BTW weird `9.4.0` works and `8.4` fails ...
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rmannibucau (via GitHub)" <gi...@apache.org>.
rmannibucau commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3426807128
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java:
##########
@@ -467,8 +467,16 @@ private void setInverseRelation(OpenJPAStateManager owner,
continue;
}
OpenJPAStateManager sm = (OpenJPAStateManager) pc.pcGetStateManager();
- ClassMapping cm =
- (ClassMapping) _conf.getMetaDataRepositoryInstance().getCachedMetaData(pc.getClass());
+ if (sm == null) {
Review Comment:
wonder if these null cases shouldn't throw, means enhancement is broken or setup (agent) is broken no?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3437864119
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
The reason validate() stops throwing once you swap BOOLEAN → INT is MappingInfo.mergeColumn(). When the live column is numeric (INT → Oracle NUMBER → reflected as NUMERIC) and the mapping expects VARCHAR, there's a branch that silently upgrades numeric → VARCHAR instead of reporting drift. That branch was added for the @MapKeyEnumerated ORDINAL/STRING shared-column case, so it's intentional but it also defeats validate()'s drift detection here.
It's the same thin already documented for PostgreSQL in PostgresDictionary.newColumn() (PG reports bool as Types.BIT, which is "numeric" to that code
too) -> there we remap bool → Types.BOOLEAN so the drift is seen again.
We can't reuse that trick on Oracle: pre-23c there's no native BOOLEAN, and an INT column genuinely is a NUMBER, so numeric-vs-VARCHAR is exactly the case the code is built to tolerate.
So rather than a version guard, we could make the test induce a drift that's genuinely incompatible with the String → VARCHAR2 mapping on every Oracle version: replace the column with a BLOB on Oracle (keep BOOLEAN elsewhere). OracleDictionary.getColumns() reports BLOB as Types.BLOB, which is neither varchar- nor numeric-compatible, so validate() throws as expected. Something like:
```
boolean isOracle = dict instanceof OracleDictionary;
stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
if (isOracle) {
// Oracle has no native BOOLEAN before 23c, and an INT/NUMBER replacement
// is silently coerced to VARCHAR by MappingInfo.mergeColumn (the numeric<->varchar
// tolerance added for @MapKeyEnumerated), so validate() wouldn't detect the drift.
// BLOB is genuinely incompatible with the String -> VARCHAR mapping on every Oracle version.
stmt.executeUpdate("ALTER TABLE UUIDEntity ADD value_ BLOB");
} else {
stmt.executeUpdate("ALTER TABLE UUIDEntity ADD COLUMN value_ BOOLEAN DEFAULT FALSE");
}
```
The alternative is to fix numeric↔varchar coercion in mergeColumn on adapt; coerce when building/adapting a schema (adapt=true), but throw when validating (adapt=false). Then validate() becomes strict on every DB, the Oracle INT drift is correctly detected, and the test needs no DB-specific branch at all. Something in that way maybe? wdyt?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3439994875
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
Million thanks for clarifications @rzo1 :))
This is something I suspect but was unsure how to find it in the code ...
I'll keep BLOB-for-everyone due to it will simplify test code (native query might be the same for all DBs)
and will add comments, something like this:
```
stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
// this test originally has BOOLEAN column but in addition of different 'ALTER TABLE' syntax
// Oracle has no native BOOLEAN before 23c, and an INT/NUMBER replacement
// is silently coerced to VARCHAR by MappingInfo.mergeColumn (the numeric<->varchar
// tolerance added for @MapKeyEnumerated), so validate() wouldn't detect the drift.
// BLOB is genuinely incompatible with the String -> VARCHAR mapping on every Oracle version.
stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BLOB");
Long n = (Long) em
.createNativeQuery("SELECT COUNT(1) FROM UUIDEntity WHERE id_ = ? AND value_ IS NULL", Long.class)
.setParameter(1, ue1.getId())
.getSingleResult();
```
Please let me know if this test might be further improved :)
Meanwhile I'll start huge Oracle test (I'm afraid it will require days on my laptop :((( )
I'll report back here
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3422045471
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -107,6 +109,11 @@ public void testTruncate() {
@Test
public void testValidate() {
EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ DBDictionary dict = getDbDictionary(emf);
+ if (dict instanceof MySQLDictionary) {
Review Comment:
I've just tested with `8.4.8` it works as expected for me without this commit :(
could you please triple-check with the script I've put into `script` folder?
It should be as easy as
```
cd script
./complex_test.sh -m=mysql:8.4.9,9.7.0
```
Meanwhile I'll run same test :)
sorry it took so long
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4727395277
Another update: `HerbDB` seems to be broken in `master` so it should be fixed separately :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3416658385
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -107,6 +109,11 @@ public void testTruncate() {
@Test
public void testValidate() {
EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ DBDictionary dict = getDbDictionary(emf);
+ if (dict instanceof MySQLDictionary) {
Review Comment:
Just confirmed: both mysql:8-oracle (8.4.9-1.el9) and mysql:lts/latest (9.7.0-1.el9) failed on TestJDBCSchemaManager#testValidate without the commit.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3585565411
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
And one of the most weird issue is this this entity: https://github.com/apache/openjpa/blob/master/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/polymorphic/Translation.java#L40
For whatever reason it has type `VIEW` in `HSQL`. I believe this is the reason why we getting:
```
Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: user lacks privilege or object not found: PUBLIC.TRANSLATIONS {stmnt 1558395480 ALTER TABLE TRANSLATIONS ADD COLUMN id BIGINT} [code=-5501, state=42501]
at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:219)
at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:203)
at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator$LoggingConnection$LoggingStatement.executeUpdate(LoggingConnectionDecorator.java:955)
at org.apache.openjpa.lib.jdbc.DelegatingStatement.executeUpdate(DelegatingStatement.java:123)
at org.apache.openjpa.jdbc.schema.SchemaTool.executeSQL(SchemaTool.java:1516)
at org.apache.openjpa.jdbc.schema.SchemaTool.addColumn(SchemaTool.java:1332)
at org.apache.openjpa.jdbc.schema.SchemaTool.buildSchema(SchemaTool.java:710)
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4476720952
Dockerized tests in postgres 11 fails:
```
[ERROR] Errors:
[ERROR] TestInputStreamLob>AbstractPersistenceTestCase.run:212->AbstractPersistenceTestCase.runBare:552->AbstractPersistenceTestCase.runBare:576->AbstractPersistenceTestCase.runTest:589->AbstractLobTest.testDataCache:221 » Rollback The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[ERROR] TestInputStreamLob>AbstractPersistenceTestCase.run:212->AbstractPersistenceTestCase.runBare:552->AbstractPersistenceTestCase.runBare:576->AbstractPersistenceTestCase.runTest:589->AbstractLobTest.testDelete:156->AbstractLobTest.insert:73 » Rollback The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[ERROR] TestInputStreamLob>AbstractPersistenceTestCase.run:212->AbstractPersistenceTestCase.runBare:552->AbstractPersistenceTestCase.runBare:576->AbstractPersistenceTestCase.runTest:589->AbstractLobTest.testInsert:78->AbstractLobTest.insert:73 » Rollback The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[ERROR] TestInputStreamLob>AbstractPersistenceTestCase.run:212->AbstractPersistenceTestCase.runBare:552->AbstractPersistenceTestCase.runBare:576->AbstractPersistenceTestCase.runTest:589->AbstractLobTest.testInsertAndSelect:83->AbstractLobTest.insert:73 » Rollback The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[ERROR] TestInputStreamLob>AbstractPersistenceTestCase.run:212->AbstractPersistenceTestCase.runBare:552->AbstractPersistenceTestCase.runBare:576->AbstractPersistenceTestCase.runTest:589->AbstractLobTest.testLifeCycleInsertFlushModify:176 » Persistence The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[ERROR] TestInputStreamLob>AbstractPersistenceTestCase.run:212->AbstractPersistenceTestCase.runBare:552->AbstractPersistenceTestCase.runBare:576->AbstractPersistenceTestCase.runTest:589->AbstractLobTest.testLifeCycleLoadFlushModifyFlush:183->AbstractLobTest.insert:73 » Rollback The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[ERROR] TestInputStreamLob>AbstractPersistenceTestCase.run:212->AbstractPersistenceTestCase.runBare:552->AbstractPersistenceTestCase.runBare:576->AbstractPersistenceTestCase.runTest:589->AbstractLobTest.testReadingMultipleTimesWithASingleConnection:196->AbstractLobTest.insert:73 » Rollback The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[ERROR] TestInputStreamLob>AbstractPersistenceTestCase.run:212->AbstractPersistenceTestCase.runBare:552->AbstractPersistenceTestCase.runBare:576->AbstractPersistenceTestCase.runTest:589->AbstractLobTest.testSetFlushAndReset:256 » Persistence The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[ERROR] TestInputStreamLob>AbstractPersistenceTestCase.run:212->AbstractPersistenceTestCase.runBare:552->AbstractPersistenceTestCase.runBare:576->AbstractPersistenceTestCase.runTest:589->AbstractLobTest.testSetResetAndFlush:240 » Persistence The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[ERROR] TestInputStreamLob>AbstractPersistenceTestCase.run:212->AbstractPersistenceTestCase.runBare:552->AbstractPersistenceTestCase.runBare:576->AbstractPersistenceTestCase.runTest:589->AbstractLobTest.testUpdate:106->AbstractLobTest.insert:73 » Rollback The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[ERROR] TestInputStreamLob>AbstractPersistenceTestCase.run:212->AbstractPersistenceTestCase.runBare:552->AbstractPersistenceTestCase.runBare:576->AbstractPersistenceTestCase.runTest:589->AbstractLobTest.testUpdateANullObjectWithoutNull:145 » Rollback The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[ERROR] TestInputStreamLob>AbstractPersistenceTestCase.run:212->AbstractPersistenceTestCase.runBare:552->AbstractPersistenceTestCase.runBare:576->AbstractPersistenceTestCase.runTest:589->AbstractLobTest.testUpdateWithNull:123->AbstractLobTest.insert:73 » Rollback The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[INFO]
[ERROR] Tests run: 3603, Failures: 0, Errors: 12, Skipped: 0
```
with stacktrace like this:
```
[ERROR] org.apache.openjpa.jdbc.meta.strats.TestInputStreamLob.testLifeCycleInsertFlushModify -- Time elapsed: 0.104 s <<< ERROR!
<openjpa-4.2.0-SNAPSHOT-r6871746 fatal general error> org.apache.openjpa.persistence.PersistenceException: The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
at org.apache.openjpa.kernel.BrokerImpl.newFlushException(BrokerImpl.java:2471)
at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2306)
at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:2197)
at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:1960)
at org.apache.openjpa.kernel.DelegatingBroker.flush(DelegatingBroker.java:1161)
at org.apache.openjpa.persistence.EntityManagerImpl.flush(EntityManagerImpl.java:1047)
at org.apache.openjpa.jdbc.meta.strats.AbstractLobTest.testLifeCycleInsertFlushModify(AbstractLobTest.java:176)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at junit.framework.TestCase.runTest(TestCase.java:177)
at org.apache.openjpa.persistence.test.AbstractPersistenceTestCase.runTest(AbstractPersistenceTestCase.java:589)
at junit.framework.TestCase.runBare(TestCase.java:142)
at org.apache.openjpa.persistence.test.AbstractPersistenceTestCase.runBare(AbstractPersistenceTestCase.java:576)
at org.apache.openjpa.persistence.test.AbstractPersistenceTestCase.runBare(AbstractPersistenceTestCase.java:552)
at junit.framework.TestResult$1.protect(TestResult.java:122)
at junit.framework.TestResult.runProtected(TestResult.java:142)
at junit.framework.TestResult.run(TestResult.java:125)
at junit.framework.TestCase.run(TestCase.java:130)
at org.apache.openjpa.persistence.test.AbstractPersistenceTestCase.run(AbstractPersistenceTestCase.java:212)
at junit.framework.TestSuite.runTest(TestSuite.java:241)
at junit.framework.TestSuite.run(TestSuite.java:236)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:90)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:316)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:240)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:214)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:155)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
Caused by: <openjpa-4.2.0-SNAPSHOT-r6871746 fatal general error> org.apache.openjpa.persistence.PersistenceException: Exception flushing output stream
at org.apache.openjpa.jdbc.sql.DBDictionary.narrow(DBDictionary.java:5524)
at org.apache.openjpa.jdbc.sql.DBDictionary.newStoreException(DBDictionary.java:5484)
at org.apache.openjpa.jdbc.sql.SQLExceptions.getStore(SQLExceptions.java:134)
at org.apache.openjpa.jdbc.sql.SQLExceptions.getStore(SQLExceptions.java:107)
at org.apache.openjpa.jdbc.sql.SQLExceptions.getStore(SQLExceptions.java:59)
at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.populateRowManager(AbstractUpdateManager.java:190)
at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:100)
at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:81)
at org.apache.openjpa.jdbc.kernel.JDBCStoreManager.flush(JDBCStoreManager.java:762)
at org.apache.openjpa.kernel.DelegatingStoreManager.flush(DelegatingStoreManager.java:146)
at org.apache.openjpa.datacache.DataCacheStoreManager.flush(DataCacheStoreManager.java:675)
at org.apache.openjpa.kernel.DelegatingStoreManager.flush(DelegatingStoreManager.java:146)
... 31 more
Caused by: org.postgresql.util.PSQLException: Exception flushing output stream
at org.postgresql.largeobject.LargeObject.close(LargeObject.java:176)
at org.apache.openjpa.jdbc.sql.PostgresDictionary.insertPostgresBlob(PostgresDictionary.java:854)
at org.apache.openjpa.jdbc.sql.PostgresDictionary.insertBlobForStreamingLoad(PostgresDictionary.java:833)
at org.apache.openjpa.jdbc.meta.strats.LobFieldStrategy.insert(LobFieldStrategy.java:107)
at org.apache.openjpa.jdbc.meta.FieldMapping.insert(FieldMapping.java:652)
at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.insert(AbstractUpdateManager.java:243)
at org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.populateRowManager(AbstractUpdateManager.java:170)
... 37 more
Caused by: java.io.IOException: Can not flush large object 16,611
at org.postgresql.largeobject.BlobOutputStream.flush(BlobOutputStream.java:217)
at org.postgresql.largeobject.LargeObject.close(LargeObject.java:174)
... 43 more
Caused by: org.postgresql.util.PSQLException: This large object has been closed.
at org.postgresql.largeobject.LargeObject.checkClosed(LargeObject.java:85)
at org.postgresql.largeobject.LargeObject.write(LargeObject.java:256)
at org.postgresql.largeobject.BlobOutputStream.flush(BlobOutputStream.java:212)
... 44 more
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4476775805
Hmmm, `postgres 11` seems to be EoLed loooong time ago ...
I'm now testing at `postgres 16`
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3700881759
##########
openjpa-integration/tck/run-tck32.sh:
##########
@@ -0,0 +1,210 @@
+#!/bin/bash
+#
+# 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.
+#
+
+TCK_VERSION="${TCK_VERSION:-3.2.0}"
+TCK_BASE="${TCK_VERSION:0:3}"
+
+SCRIPT_ROOT=$(cd -- $(dirname "${0}") && pwd)
+PROJECT_ROOT="$(cd "${SCRIPT_ROOT}/../.." && pwd)"
+
+# derby is removed for now
+# mysql 8.0 is broken! db.delimiter='!' breaks connection
+declare -A FULL_DB_LIST=(
+ [mysql]=mysql
+ [postgresql]=postgresql
+ [mssql]=mssqlserver
+ [oracle]=oracle
+)
+
+declare -A VERSIONS=(
+ [mysql]='8.4.8' # 8.4.8 9.4.0
+ [postgresql]='16'
+)
+
+#
+# Script to download, setup and run the JPA 3.2 TCK against OpenJPA
+# using DB selected.
+#
+# Usage:
+# ./run-tck32.sh # Run full TCK against postgres:16
+# DB_VERSION=18 ./run-tck32.sh # Run full TCK against postgres:18
+# DB_TYPE=mysql ./run-tck32.sh # Run full TCK against mysql:8.4.8
+# DB_HOST=myhost:5432 ./run-tck32.sh # Custom DB host
+# OPENJPA_VERSION=4.2.0-SNAPSHOT ./run-tck32.sh # Custom OpenJPA version
+#
+# Prerequisites:
+# - OpenJPA must be built and installed in local Maven repo
+# (run 'mvn install -DskipTests' from the project root)
+# - Java 17+ and Maven 3.x
+#
+
+set -e
+
+# Check required commands
+MISSING=""
+for cmd in java mvn curl unzip grep sed; do
+ if ! command -v "$cmd" &>/dev/null; then
+ MISSING="${MISSING} - ${cmd}\n"
+ fi
+done
+if [[ -n "$MISSING" ]]; then
+ echo "ERROR: The following required commands are not available:"
+ echo -e "$MISSING"
+ echo "Please install them before running this script."
+ exit 1
+fi
+
+stopAll() {
+ for profile in ${!FULL_DB_LIST[@]}; do
+ echo "Stopping dockerized ${profile}"
+ mvn -N -Ptest-${profile}-docker -f ${PROJECT_ROOT} -Ddocker.stopNamePattern=${profile:0:8}* docker:stop -Ddocker.showLogs
+ done
+}
+
+stopAll
+
+TCK_URL="https://download.eclipse.org/jakartaee/persistence/${TCK_BASE}/jakarta-persistence-tck-${TCK_VERSION}.zip"
+TCK_DIR="${SCRIPT_ROOT}/target/tck32"
+TCK_ZIP="${TCK_DIR}/jakarta-persistence-tck-${TCK_VERSION}.zip"
+TCK_HOME="${TCK_DIR}/persistence-tck"
+OPENJPA_VERSION="${OPENJPA_VERSION:-4.2.0-SNAPSHOT}"
+START_DOCKER=
+
+if [[ -z "${DB_HOST}" ]]; then
+ START_DOCKER=1
+fi
+
+DB_TYPE="${DB_TYPE:-postgresql}"
+DB_HOST="${DB_HOST:-localhost:5555}"
+DB_USER="${DB_USER:-tcktest}"
+DB_PASSWORD="${DB_PASSWORD:-tcktest}"
+DB_NAME="${DB_NAME:-tcktest}"
+DB_URL=""
+declare -a JPROPS=()
+
+DB_HOST_ONLY="${DB_HOST%%:*}"
+DB_PORT="${DB_HOST##*:}"
+
+TCK_DB_TYPE="${FULL_DB_LIST[${DB_TYPE}]}"
+
+setProps() {
+ local ver="${VERSIONS[${DB_TYPE}]}"
+ if [[ -n "${DB_VERSION}" ]]; then
+ ver="${DB_VERSION}"
+ fi
+ if [[ -n "${VERSIONS[${DB_TYPE}]}" ]]; then
+ JPROPS+=("-D${DB_TYPE}.server.version=${ver}")
+ fi
+
+ case ${DB_TYPE} in
+ mysql)
+ DB_URL="jdbc:mysql://${DB_HOST}/${DB_NAME}?useSSL=false&allowPublicKeyRetrieval=true&transformedBitIsBoolean=true"
+ ;;
+ postgresql)
+ DB_URL="jdbc:postgresql://${DB_HOST}/${DB_NAME}"
+ ;;
+ mssql)
+ DB_NAME=""
+ DB_URL="jdbc:sqlserver://${DB_HOST};sendTimeAsDatetime=false;trustServerCertificate=true"
+ ;;
+ oracle)
+ JPROPS+=("-Dopenjpa.oracle.SID=${DB_NAME}")
+ DB_NAME="XE"
+ DB_URL="jdbc:oracle:thin:@${DB_HOST}:${DB_NAME}"
+ ;;
+ esac
+ JPROPS+=("-Ddocker.external.${DB_TYPE}.port=${DB_PORT}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.dbname=${DB_NAME}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.username=${DB_USER}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.password=${DB_PASSWORD}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.url=${DB_URL}")
+}
+
+setProps
+
+if [[ -n "${START_DOCKER}" ]]; then
+ echo "Starting dockerized ${DB_TYPE}"
+ mvn -N -f ${PROJECT_ROOT} -Ptest-${DB_TYPE}-docker "${JPROPS[@]}" docker:start -Ddocker.showLogs
+fi
+
+GF_VERSION="${GF_VERSION:-8.0.0}"
+
+echo "=== JPA ${TCK_BASE} TCK Runner for OpenJPA ==="
+echo "OpenJPA version: ${OPENJPA_VERSION}"
+echo "TCK version: ${TCK_VERSION}"
+echo "GlassFish: ${GF_VERSION}"
+echo "Database: ${DB_TYPE} (${DB_HOST}/${DB_NAME})"
+echo ""
+
+# Step 1: Download TCK if not present
+mkdir -p "${TCK_DIR}"
+if [[ ! -f "${TCK_ZIP}" ]]; then
+ echo "Downloading JPA ${TCK_BASE} TCK..."
+ curl -sL -o "${TCK_ZIP}" "${TCK_URL}"
+ echo "Downloaded."
+else
+ echo "TCK zip already present, skipping download."
+fi
+
+# Step 2: Extract TCK
+if [[ ! -d "${TCK_HOME}" ]]; then
+ echo "Extracting TCK..."
+ cd "${TCK_DIR}" && unzip -q "${TCK_ZIP}"
+ echo "Extracted."
+else
+ echo "TCK already extracted, skipping."
+fi
+
+# Step 3: Install TCK artifacts into local Maven repo
+echo "Installing TCK artifacts..."
+cd "${TCK_HOME}/artifacts" && bash artifact-install.sh "${TCK_VERSION}"
+echo "TCK artifacts installed."
+
+# Step 4: Patch TCK pom.xml to add OpenJPA profile (if not already patched)
+TCK_POM="${TCK_HOME}/bin/pom.xml"
+if [[ -z "$(grep '<id>openjpa</id>' "${TCK_POM}")" ]]; then
+ echo "Adding OpenJPA profile to TCK pom.xml..."
+
+ sed '/<\/profiles>/,$d' "${TCK_POM}" > temp
+ cat "${SCRIPT_ROOT}/tck32-openjpa-profile.xml" >> temp
+ sed '/<\/profiles>/,$!d' "${TCK_POM}" >> temp
+ mv temp "${TCK_POM}"
+
+ echo "OpenJPA profile added."
+else
+ echo "OpenJPA profile already present in TCK pom.xml."
+fi
+
+echo ""
+echo "=== Preparing ${DB_TYPE} database ==="
Review Comment:
I'll perform clean-up (missing DBs are being created by maven and dropped by `docker:remove` ...)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4991223187
Its already fine for 17/21 😀
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4992471760
Hello All,
so far testing matrix seems to be OK:
```
Passed -- postgresql_11
Failed -- postgresql_16
Failed -- postgresql_18
Passed -- hsqldb
Passed -- h2
Passed -- mariadb
Passed -- derby
Passed -- mssql
Passed -- mysql_8.0
Passed -- mysql_8.4.8
Passed -- mysql_9.4.0
```
Oracle was skipped due to I, sort of, scared of it :) (waiting for 2 weeks last time ... :))
Postgres: `16`, `18` - failed for me with
```
[ERROR] org.apache.openjpa.persistence.lockmgr.TestPessimisticLocks.testQueryAfterFindWithPessimisticLocks -- Time elapsed: 0.158 s <<< FAILURE!
junit.framework.AssertionFailedError: Unexpected find succeeded. Should throw a PessimisticLockException.
at junit.framework.Assert.fail(Assert.java:57)
at junit.framework.TestCase.fail(TestCase.java:223)
at org.apache.openjpa.persistence.lockmgr.TestPessimisticLocks.testQueryAfterFindWithPessimisticLocks(TestPessimisticLocks.java:303)
..... more frames dropped
```
which is weird, but I have no idea how it can be fixed (and why is it differs from `11` ...
I'll try to run TCK
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4999687353
You are right @rzo1, for whatever reason the test was red for me
Reverted and `GREEN` :)
I'll try to add parametrization and perform more tests
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3689098373
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java:
##########
@@ -170,23 +172,49 @@ public ResultObjectProvider executeQuery(StoreQuery q, Object[] params, Range ra
try {
DBDictionary dict = _store.getDBDictionary();
Connection conn = _store.getConnection();
+
+ // PostgreSQL requires auto-commit off for procedures
+ // that return REF_CURSOR (cursor lives within transaction)
+ boolean resetAutoCommit = false;
Review Comment:
Fixed in 88e7709470c1b9e8299c5e51554e127d871b0e94. `resetAutoCommit` is now handed over to the `XROP` together with the connection (`XROP#setConnection`): since a REF_CURSOR is only valid inside the transaction that produced it, the connection stays open while the provider is in use and `XROP#close()` now commits, restores `autoCommit=true` and closes the connection in a `finally` after closing the statement. On the error path, `executeQuery` closes the `CallableStatement`, rolls back, restores `autoCommit` and closes the connection before rethrowing, so a failing `prepareCall`/`rop.open()` no longer leaks the connection.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3761843237
##########
openjpa-project/src/doc/manual/jpa_overview_pc.xml:
##########
@@ -1163,7 +1164,7 @@ data structure.
lifecycle callbacks
</seealso>
</indexterm>
-<ulink url="http://download.oracle.com/javaee/6/api/javax/persistence/PreUpdate.html">
+<ulink url="https://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/postupdate">
Review Comment:
Fixed
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3761215139
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaTool.java:
##########
@@ -479,71 +509,140 @@ protected void deleteTableContents()
Collection<Table> tables = new LinkedHashSet<>();
for (Schema schema : schemas) {
Table[] ts = schema.getTables();
- for (Table t : ts) {
- tables.add(t);
- }
+ Collections.addAll(tables, ts);
}
Table[] tableArray = tables.toArray(new Table[tables.size()]);
Connection conn = _ds.getConnection();
+ // Truncate is a best-effort operation: the repo SchemaGroup may
+ // declare tables the dialect never actually created (e.g.
+ // OPENJPA_SEQUENCE_TABLE on dialects that prefer native sequences,
+ // or tables in other schemas). Log missing-table errors instead of
+ // aborting.
+ boolean savedIgnore = _ignoreErrs;
+ _ignoreErrs = true;
try {
String[] sql = _conf.getDBDictionaryInstance()
.getDeleteTableContentsSQL(tableArray, conn);
if (!executeSQL(sql)) {
_log.warn(_loc.get("delete-table-contents"));
}
} finally {
+ _ignoreErrs = savedIgnore;
closeConnection(conn);
}
}
- protected void executeScript() throws SQLException {
- if (_scriptToExecute == null) {
- _log.warn(_loc.get("generating-execute-script-not-defined"));
- return;
+ private BufferedReader getScriptReader() throws IOException {
+ BufferedReader reader = null;
+ if (_scriptReader != null) {
+ reader = (_scriptReader instanceof BufferedReader br) ? br : new BufferedReader(_scriptReader);
+ } else {
+ URL url = null;
+ // Try file: URI or absolute path first
+ if (_scriptToExecute.startsWith("file:")) {
+ try {
+ url = new URI(_scriptToExecute).toURL();
+ } catch (Exception e) {
+ // fall through to classloader lookup
+ }
+ } else {
+ File f = new File(_scriptToExecute);
+ if (f.isAbsolute() && f.exists()) {
+ url = f.toURI().toURL();
+ }
+ }
+ // Fall back to classloader resource lookup
+ if (url == null) {
+ url = _conf.getClassResolverInstance()
+ .getClassLoader(SchemaTool.class, null)
+ .getResource(_scriptToExecute);
+ }
+ if (url == null) {
+ _log.error(_loc.get("generating-execute-script-not-found", _scriptToExecute));
+ return null;
+ }
+ _log.info(_loc.get("generating-execute-script", _scriptToExecute));
+ reader = new BufferedReader(new InputStreamReader(url.openStream()));
}
+ return reader;
+ }
- URL url = AccessController.doPrivileged(
- J2DoPrivHelper.getResourceAction(_conf.getClassResolverInstance().
- getClassLoader(SchemaTool.class, null), _scriptToExecute));
-
- if (url == null) {
- _log.error(_loc.get("generating-execute-script-not-found", _scriptToExecute));
+ protected void executeScript() throws SQLException {
+ if (_scriptReader == null && StringUtil.isBlank(_scriptToExecute)) {
+ _log.warn(_loc.get("generating-execute-script-not-defined"));
return;
}
- _log.info(_loc.get("generating-execute-script", _scriptToExecute));
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new InputStreamReader(url.openStream()));
- String sql;
+ try (BufferedReader reader = getScriptReader()) {
+ if (reader == null) {
+ return;
+ }
+ String line;
List<String> script = new ArrayList<>();
- while ((sql = reader.readLine()) != null) {
- sql = sql.trim();
- if (sql.startsWith("--") || sql.startsWith("/*") || sql.startsWith("//")) {
+ StringBuilder stmt = new StringBuilder();
+ AtomicBoolean insideMultilineComments = new AtomicBoolean(false);
+ Function<String, String> stripComments = (str) -> {
Review Comment:
Commited the suggested fix with a correspondent test, but I think this should be addressed better in the future, maybe with a regex parsing of the scripts.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rmannibucau (via GitHub)" <gi...@apache.org>.
rmannibucau commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3781962518
##########
.gitignore:
##########
@@ -11,3 +11,11 @@ nbactions*.xml
.checkstyle
.vscode
+.claude
+CLAUDE.md
+tck-dev
+docker-compose.yml
+pgdata
+openjpa-xmlstore/jdbc*
Review Comment:
ok to drop for me while we have some in-memory/local alternatives (h2 and hsqldb are more than great there)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3780883282
##########
openjpa-integration/daytrader/pom.xml:
##########
@@ -94,6 +94,7 @@
<goals>
<goal>unpack</goal>
</goals>
+ <?m2e ignore?>
Review Comment:
all occurrences are removed
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801798987
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
Review Comment:
Do you mean https://testcontainers.com/modules/oracle-xe/ ?
How it can be used as Maven profile? :))
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3803778590
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypesafeCriteria.java:
##########
@@ -1781,5 +1789,168 @@ public void testIdClass() {
assertEquivalence(cq, jpql);
}
+
+ public void testLeft() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where left(p.name, 4) = 'John'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.left(c.get("name"), 4), "John"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testRight() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where RIGHT(p.name, 3) = 'Doe'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.right(c.get("name"), 3), "Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testReplace() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ String jpql = "select p from Person p where REPLACE(p.name, 'ohn', 'ack') = 'Jack Fitzgerald Doe'";
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.replace(c.get("name"), "ohn", "ack"), "Jack Fitzgerald Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ /**
+ * JPA 3.2 Criteria UNION must execute end-to-end and produce the
+ * same SQL as the JPQL UNION form. We don't compare row counts
+ * because TestTypesafeCriteria shares a static EMF with other test
+ * classes and we don't want to seed shared tables.
+ */
+ public void testCriteriaUnion() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 30));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.equal(r2.get("name"), "Ugo"));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> union = cb.union(q1, q2);
+ assertNotNull(em.createQuery(union).getResultList());
+ }
+
+ public void testCriteriaUnionAll() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 25));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.gt(r2.<Integer>get("age"), 30));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> unionAll = cb.unionAll(q1, q2);
+ assertNotNull(em.createQuery(unionAll).getResultList());
+ }
+
+ public void testCriteriaExcept() {
Review Comment:
This test fails at `Oracle:18.4.0`
```
Caused by: Error : 933, Position : 53, Sql = SELECT t0.name FROM CompUser t0 WHERE (t0.age > :1 ) EXCEPT SELECT t0.name FROM CompUser t0 WHERE (t0.age > :2 ), OriginalSql = SELECT t0.name FROM CompUser t0 WHERE (t0.age > ?) EXCEPT SELECT t0.name FROM CompUser t0 WHERE (t0.age > ?), Error Msg = ORA-00933: SQL command not properly ended
at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:513)
... 56 more
```
Steps:
`mvn -N -Ptest-oracle-docker docker:start -Ddocker.showLogs`
`cd openjpa-persistence-jdbc/`
`mvn clean test -Ptest-oracle-docker -Dtest=TestTypesafeCriteria`
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3800971488
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/common/apps/CompUser.java:
##########
@@ -66,6 +67,9 @@ public class CompUser {
@Enumerated
@Basic
private CreditRating creditRating;
+
+ @Version
Review Comment:
@rzo1 I've added CompVerUser and now test fails ....
Could you please take a look?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801567144
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestExternalizedParameter.java:
##########
@@ -56,48 +56,44 @@ public void setUp() throws Exception {
}
}
+ /**
+ * Verifies that a query with a non-externalized parameter executes
+ * correctly.
+ */
public void testNoFalseAlarmOnExternalizedParameterDetection() {
String jpql = "select b from Book b where b.title=:title";
EntityManager em = emf.createEntityManager();
- QueryExpressions[] exps = getExpressions(em.createQuery(jpql)
+ List<?> result = em.createQuery(jpql)
.setParameter("title","XYZ")
- .getResultList());
- assertNotNull(exps);
-
- assertFalse(isUsingExternalizedParameter(exps[0]));
+ .getResultList();
+ assertNotNull(result);
}
+ /**
+ * Verifies that a query with an externalized parameter (token maps
+ * to an enum via ExternalValues) executes correctly.
+ */
public void testCanDetectExternalizedSingleParameterValue() {
Review Comment:
@rzo1 these were your changes :))
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801954338
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/InstantVersionStrategy.java:
##########
@@ -0,0 +1,64 @@
+/*
+ * 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.meta.strats;
+
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.meta.JavaTypes;
+
+/**
+ * Uses an {@link Instant} for optimistic versioning.
+ *
+ * @since 4.2.0
+ */
+public class InstantVersionStrategy
+ extends ColumnVersionStrategy {
+
+ private static final long serialVersionUID = 1L;
+ public static final String ALIAS = "version-instant";
+
+ @Override
+ public String getAlias() {
+ return ALIAS;
+ }
+
+ @Override
+ protected int getJavaType() {
+ return JavaTypes.INSTANT;
+ }
+
+ @Override
+ protected Object nextVersion(Object version) {
+ return Instant.now();
Review Comment:
@rmannibucau I can change the code to be `return Instant.now().truncatedTo(ChronoUnit.MILLIS);` would it be better?
What if user will need better precision?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5326503406
> @rzo1 could you please add [#144 (comment)](https://github.com/apache/openjpa/pull/144#issuecomment-5011202275) to the table?
>
> And let's wait for @rmannibucau to resolve at least something from this huge table ....
Updated + Status Column ;-) - so lets wait and update it so we can proceed with the Jiras later on.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4477287848
Unfortunately I'm not really expert in OpenJPA :(
I'll try to debug and will report back
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3425029454
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -107,6 +109,11 @@ public void testTruncate() {
@Test
public void testValidate() {
EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ DBDictionary dict = getDbDictionary(emf);
+ if (dict instanceof MySQLDictionary) {
Review Comment:
My results:
```
Passed -- mysql_8.4.9
Passed -- mysql_9.7.0
```
with https://github.com/apache/openjpa/pull/144/commits/8d1befb3798ca9a1860ce56b01c8284da46114c8 locally reverted
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4720577081
Ok for me.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3425712856
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -107,6 +109,11 @@ public void testTruncate() {
@Test
public void testValidate() {
EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ DBDictionary dict = getDbDictionary(emf);
+ if (dict instanceof MySQLDictionary) {
Review Comment:
My tests failed because I didn't set transformedBitIsBoolean=true in jdbc connection. Without that configuration, the test fails. Reverted the commit.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4709630906
Hello all,
little status update:
all `in-memory` and `dockerized` DBs listed in `pom.xml` are currently green for me except for
```
Oracle
HerbDB
```
I'm trying to fix Oracle :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3414784383
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -107,6 +109,11 @@ public void testTruncate() {
@Test
public void testValidate() {
EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ DBDictionary dict = getDbDictionary(emf);
+ if (dict instanceof MySQLDictionary) {
Review Comment:
Hi, @solomax! I get a failed test on mysql:lts (docker, version 8.4.8-1.el9). Inspecting it, I found that the tinybit used for bool makes the testValidate fail because MysqlDbDictionary treats it as a number and then the actual test (should throw SchemaValidationException) fails.
Tested it again here without my exception and it fails.
I'm using maven:3-eclipse-temunin-17 (docker) to test the codebase, and mysql:lts (docker) as db target. Testing on pg (18, 17), h2 (2), hsql and mariadb (lts and latest) are all green here.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3500357167
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
Finally got some errors:
```
Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: ORA-00904: "RIGHT": invalid identifier
{prepstmnt 1469385865 SELECT t0.id, t0.DTYPE, t0.name FROM CR_PSN t0 WHERE (RIGHT(t0.name, 3) = ?)} [code=904, state=42000]
```
```
Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: ORA-00904: "CURRENT_TIME": invalid identifier
{prepstmnt 238780535 SELECT CURRENT_TIME FROM CR_ODR t0 WHERE (t0.id = ?)} [code=904, state=42000]
```
```
Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: ORA-00904: "CEILING": invalid identifier
{prepstmnt 2098979980 SELECT t0.id, t0.balance, t1.id, t1.accountNum, t2.id, t2.city, t2.country, t2.county, t2.state, t2.street, t3.userid, t3.DTYPE, t3.age, t3.compName, t3.creditRating, t3.name, t2.zipCode, t1.balanceOwed, t1.creditRating, t1.filledOrderCount, t1.firstName, t1.lastName, t1.name, t1.status, t0.loan, t0.name, t4.id, t4.DTYPE, t4.name, t0.PRODUCT_PID FROM CR_ACCT t0 LEFT OUTER JOIN CR_CUST t1 ON t0.CUSTOMER_ID = t1.id LEFT OUTER JOIN CR_PSN t4 ON t0.OWNER_ID = t4.id LEFT OUTER JOIN CR_ADDR t2 ON t1.ADDRESS_ID = t2.id LEFT OUTER JOIN CompUser t3 ON t2.id = t3.ADD_ID WHERE (CEILING(t0.balance) = ?)} [code=904, state=42000]
```
```
Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: ORA-00933: SQL command not properly ended
{prepstmnt 196483674 SELECT t0.name FROM CompUser t0 WHERE (t0.age > ?) EXCEPT SELECT t0.name FROM CompUser t0 WHERE (t0.age > ?)} [code=933, state=42000]
```
I'll wait for some more, meanwhile will try to fix these :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5002155761
Just commited updated `run-tck32.sh`
It is now able to run TCK against MySql with `DB_TYPE=mysql ./run-tck32.sh` (version can also be specified
My results are:
`[ERROR] Tests run: 2134, Failures: 0, Errors: 145, Skipped: 4`
I'll try to take a look at all this later :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3592394593
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
Thanks a lot @rzo1!
HSQL run is green for me. I'll re-run everything one more time and then will try to run TCK :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4995304728
I ran profile test-derby with jdk17 with no issues. Checking the github logs, it seems the problem was that elusive ghostly kubernetes error again. Still running oracle tests (on oracle-xe-18 and oracle-xe-21)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4989807465
> But our build is RED if Java-21 is used (all proxy related tests fails)
What exactly?
For me:
- TestProxyManager (openjpa-kernel): 44/44 pass on Temurin 21.0.4
- All 17 proxy test classes in openjpa-persistence-jdbc (169 tests): all pass on JDK 21 with Derby
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3761796073
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Left.java:
##########
@@ -0,0 +1,164 @@
+/*
+ * 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.JavaSQLTypes;
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.jdbc.sql.SQLBuffer;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.kernel.Filters;
+import org.apache.openjpa.kernel.exps.ExpressionVisitor;
+import org.apache.openjpa.meta.ClassMetaData;
+
+/**
+ * Take the left part of a string.
+ *
+ * @author Abe White
+ * @author Paulo Cristovão Filho
+ * @since 4.2.0
+ */
+public class Left
+ extends AbstractVal {
+
+
+ private static final long serialVersionUID = 1L;
+ private final Val _val1;
+ private final Val _val2;
+ private ClassMetaData _meta = null;
+
+ /**
+ * Constructor. Provide the string and length to operate on
+ */
+ public Left(Val val1, Val val2) {
+ _val1 = val1;
+ _val2 = val2;
+ }
+
+ public Val getVal1() {
+ return _val1;
+ }
+
+ public Val getVal2() {
+ return _val2;
+ }
+
+ @Override
+ public ClassMetaData getMetaData() {
+ return _meta;
+ }
+
+ @Override
+ public void setMetaData(ClassMetaData meta) {
+ _meta = meta;
+ }
+
+ @Override
+ public Class getType() {
+ return String.class;
+ }
+
+ @Override
+ public void setImplicitType(Class type) {
+ }
+
+ @Override
+ public ExpState initialize(Select sel, ExpContext ctx, int flags) {
+ ExpState s1 = _val1.initialize(sel, ctx, 0);
+ ExpState s2 = _val2.initialize(sel, ctx, 0);
+ return new BinaryOpExpState(sel.and(s1.joins, s2.joins), s1, s2);
+ }
+
+ @Override
+ public void select(Select sel, ExpContext ctx, ExpState state,
+ boolean pks) {
+ sel.select(newSQLBuffer(sel, ctx, state), this);
+ }
+
+ @Override
+ public void selectColumns(Select sel, ExpContext ctx, ExpState state,
+ boolean pks) {
+ BinaryOpExpState bstate = (BinaryOpExpState) state;
+ _val1.selectColumns(sel, ctx, bstate.state1, true);
+ _val2.selectColumns(sel, ctx, bstate.state2, true);
+ }
+
+ @Override
+ public void groupBy(Select sel, ExpContext ctx, ExpState state) {
+ sel.groupBy(newSQLBuffer(sel, ctx, state));
+ }
+
+ @Override
+ public void orderBy(Select sel, ExpContext ctx, ExpState state,
+ boolean asc) {
+ sel.orderBy(newSQLBuffer(sel, ctx, state), asc, false, getSelectAs());
+ }
+
+ private SQLBuffer newSQLBuffer(Select sel, ExpContext ctx, ExpState state) {
+ calculateValue(sel, ctx, state, null, null);
+ SQLBuffer buf = new SQLBuffer(ctx.store.getDBDictionary());
+ appendTo(sel, ctx, state, buf, 0);
+ return buf;
+ }
+
+ @Override
+ public Object load(ExpContext ctx, ExpState state, Result res)
+ throws SQLException {
+ return Filters.convert(res.getObject(this,
+ JavaSQLTypes.JDBC_DEFAULT, null), getType());
+ }
+
+ @Override
+ public void calculateValue(Select sel, ExpContext ctx, ExpState state,
+ Val other, ExpState otherState) {
+ BinaryOpExpState bstate = (BinaryOpExpState) state;
+ _val1.calculateValue(sel, ctx, bstate.state1, null, null);
+ _val2.calculateValue(sel, ctx, bstate.state2, null, null);
+ }
+
+ @Override
+ public int length(Select sel, ExpContext ctx, ExpState state) {
+ return 1;
+ }
+
+ @Override
+ public void appendTo(Select sel, ExpContext ctx, ExpState state,
+ SQLBuffer sql, int index) {
+ BinaryOpExpState bstate = (BinaryOpExpState) state;
+ FilterValue str = new FilterValueImpl(sel, ctx, bstate.state1, _val1);
+ FilterValue len = new FilterValueImpl(sel, ctx, bstate.state2, _val2);
+
+ ctx.store.getDBDictionary().left(sql, str, len);
+ }
+
+ @Override
+ public void acceptVisit(ExpressionVisitor visitor) {
+ visitor.enter(this);
+ _val1.acceptVisit(visitor);
+ _val2.acceptVisit(visitor);
+ visitor.exit(this);
+ }
+
+ @Override
+ public int getId() {
+ return Val.SUBSTRING_VAL;
Review Comment:
Fixed found issues
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3771749945
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java:
##########
@@ -477,7 +823,160 @@ public boolean isLoaded(Object entity, String attribute) {
return (OpenJPAPersistenceUtil.isManagedBy(this, entity) &&
(OpenJPAPersistenceUtil.isLoaded(entity, attribute) == LoadState.LOADED));
}
-
+
+ @Override
+ public <E> boolean isLoaded(E entity, Attribute<? super E, ?> attribute) {
+ return isLoaded(entity, attribute.getName());
+ }
+
+ @Override
+ public SchemaManager getSchemaManager() {
+ if (!this.isOpen()) {
+ throw new IllegalStateException("EntityManagerFactory is closed.");
+ }
+ return new SchemaManagerImpl(_factory);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <R> R callInTransaction(Function<EntityManager, R> work) {
+ EntityManager em = createEntityManager();
+ boolean startedTransaction = false;
+ boolean jtaTransaction = getTransactionType() == PersistenceUnitTransactionType.JTA;
+ Broker broker = em.unwrap(Broker.class);
+ try {
+ if (jtaTransaction) {
+ if (!broker.syncWithManagedTransaction()) {
+ broker.begin();
+ startedTransaction = true;
+ }
+ } else {
+ em.getTransaction().begin();
+ startedTransaction = true;
+ }
+ R result = work.apply(em);
+ if (startedTransaction) {
+ if (jtaTransaction) {
+ broker.commit();
+ } else {
+ em.getTransaction().commit();
+ }
+ }
+ // For unenhanced (runtime-subclassed) entities, the user's function
+ // may return an original POJO that was passed to persist().
+ // Entities loaded via find() on other EMs are subclass instances,
+ // causing getClass() mismatches in equals(). To ensure consistent
+ // class identity, re-find managed entities from the database so that
+ // the returned instance is a subclass (matching what find() returns).
+ if (result != null && em.contains(result)) {
Review Comment:
Gated the re-find block only for results that are not enhanced classes as defined by OpenJPAPersistenceUtil#toPC
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3549830342
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
It might be a thing to mount the data dirs from the containers to tmpfs - should speed up things.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3546705165
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
@solomax, I've setup a local environment with Oracle XE to track the issues you found. Confirmed that the error with CEILING is still there, although the RIGHT issue is resolved.
On openjpa-persistence-jdbc, found failures or errors in:
- TestTypesafeCriteria#testCeilingExpression CEILING not supported
- TestBiDirectionalJoinTable expected <7>, got <3> or <4> when setting up
- TestSchemaGenerationProperties#testSchemaGenScriptCreate Table AUTOINCPC3 should have been created in the DB, but does not exists
- TestEJBQLFunction#testTypecastAsString expected:<1> but was:<0>
- TestEJBQLFunction#testTypecastAsStringOnSelect expected <23> but was <23 many spaces>
- TestEJBQLFunction#testExtractHourFromLocalTime CURRENT_TIME not supported by db
- TestEJBQLFunction#testExtractQUARTER
- TestEJBQLFunction#testExtractTimeFromInstant
- TestEJBQLFunction#testExtractTimeFromLocalTime
- TestEJBQLFunction#testExtractWEEK
- TestJava8TimeTypes#testGetCurrentLocalTime
- TestDdlOptions#testColumnOptionsInDdl DDL should contain column options
I'm running the tests against oracle dababase/express:latest.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3556202606
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
`hsqldb` errors:
I'll try to check them ...
Additionally will try to check `postgres-16`, `postgres-18` ...
```
[ERROR] Failures:
[ERROR] TestEmbeddable>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testEmbeddableContainingRelationWithGeneratedKey:314->createEmbeddableContainingRelationWithGeneratedKey:2802
[ERROR] TestJPQLScalarExpressions>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testSimpleCaseExpressions:212 the result is not male expected:<Male> but was:<Male >
[ERROR] TestEJBQLFunction>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testCEILINGFunc:554 expected:<154> but was:<153>
[ERROR] TestEJBQLFunction>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testCEILINGFuncNegative:568 expected:<-152> but was:<-153>
[ERROR] TestEJBQLFunction>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testFLOORFunc:596 expected:<152> but was:<153>
[ERROR] Errors:
[ERROR] TestMultiEMFCacheModes>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testCacheRefreshModeRefresh:88 » Persistence The database dictionary in use ("class org.apache.openjpa.jdbc.sql.HSQLDictionary") reports that it does not have feature "SupportsSelectForUpdate". This feature is needed to complete the current operation. To force OpenJPA to try to use the feature anyway, set the following property:
openjpa.jdbc.DBDictionary: SupportsSelectForUpdate=<value>
[ERROR] TestMultiEMFCacheModes>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testCacheRefreshModeRefreshDelete:167 » InvalidState This operation failed for some instances. See the nested exceptions array for details.
[ERROR] TestTablePerClassInheritanceWithAbstractRoot>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testConsistency:111 » Persistence user lacks privilege or object not found: PUBLIC.TRANSLATIONS {stmnt 957505228 ALTER TABLE TRANSLATIONS ADD COLUMN id BIGINT} [code=-5501, state=42501]
[ERROR] TestTablePerClassInheritanceWithAbstractRoot>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testEntityTypeForTablePerClassInheritance:170->populate:69 » Persistence user lacks privilege or object not found: PUBLIC.TRANSLATIONS {stmnt 1227811506 ALTER TABLE TRANSLATIONS ADD COLUMN id BIGINT} [code=-5501, state=42501]
[ERROR] TestJPQLScalarExpressions>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testGeneralCaseExpressions:323 » Argument Failed to execute query "select e.name, CASE WHEN e.age = 11 THEN org.apache.openjpa.persistence.common.apps.CompUser$CreditRating.POOR WHEN e.age = 35 THEN org.apache.openjpa.persistence.common.apps.CompUser$CreditRating.GOOD ELSE org.apache.openjpa.persistence.common.apps.CompUser$CreditRating.EXCELLENT END FROM CompUser e ORDER BY e.age". Check the query syntax for correctness. See nested exception for details.
[ERROR] TestEJBQLFunction>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testExtractWEEK:798 » Persistence unexpected token: WEEK in statement [SELECT t0.userid, t0.DTYPE, t0.version, t1.id, t1.city, t1.country, t1.streetAd, t2.userid, t2.DTYPE, t2.version, t2.age, t2.compName, t2.creditRating, t2.name, t2.nameAsLob, t1.zipcode, t0.age, t0.compName, t0.creditRating, t0.name, t0.nameAsLob FROM CompUser t0 LEFT OUTER JOIN Address t1 ON t0.ADD_ID = t1.id LEFT OUTER JOIN CompUser t2 ON t1.id = t2.ADD_ID WHERE (EXTRACT(WEEK FROM DATE '2006-03-21' ) <= ?)] {SELECT t0.userid, t0.DTYPE, t0.version, t1.id, t1.city, t1.country, t1.streetAd, t2.userid, t2.DTYPE, t2.version, t2.age, t2.compName, t2.creditRating, t2.name, t2.nameAsLob, t1.zipcode, t0.age, t0.compName, t0.creditRating, t0.name, t0.nameAsLob FROM CompUser t0 LEFT OUTER JOIN Address t1 ON t0.ADD_ID = t1.id LEFT OUT
ER JOIN CompUser t2 ON t1.id = t2.ADD_ID WHERE (EXTRACT(WEEK FROM {d '2006-03-21'}) <= ?)} [code=-5581, state=42581]
[ERROR] TestEJBQLFunction>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->AbstractPersistenceTestCase.runTest:590->testROUNDFunc:634 » Argument Failed to execute query "SELECT ROUND(SUM(c.age)/7.0, 3) FROM CompUser c". Check the query syntax for correctness. See nested exception for details.
[ERROR] TestHSQLSequence>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->setUp:80 » Persistence unexpected token: NSSEQ in statement [DROP SEQUENCE entityE nsseq gen] {DROP SEQUENCE entityE nsseq gen} [code=-5581, state=42581]
[ERROR] TestHSQLSequence>AbstractPersistenceTestCase.run:213->AbstractPersistenceTestCase.runBare:553->AbstractPersistenceTestCase.runBare:577->setUp:80 » Persistence unexpected token: NSSEQ in statement [DROP SEQUENCE entityE nsseq gen] {DROP SEQUENCE entityE nsseq gen} [code=-5581, state=42581]
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3700881759
##########
openjpa-integration/tck/run-tck32.sh:
##########
@@ -0,0 +1,210 @@
+#!/bin/bash
+#
+# 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.
+#
+
+TCK_VERSION="${TCK_VERSION:-3.2.0}"
+TCK_BASE="${TCK_VERSION:0:3}"
+
+SCRIPT_ROOT=$(cd -- $(dirname "${0}") && pwd)
+PROJECT_ROOT="$(cd "${SCRIPT_ROOT}/../.." && pwd)"
+
+# derby is removed for now
+# mysql 8.0 is broken! db.delimiter='!' breaks connection
+declare -A FULL_DB_LIST=(
+ [mysql]=mysql
+ [postgresql]=postgresql
+ [mssql]=mssqlserver
+ [oracle]=oracle
+)
+
+declare -A VERSIONS=(
+ [mysql]='8.4.8' # 8.4.8 9.4.0
+ [postgresql]='16'
+)
+
+#
+# Script to download, setup and run the JPA 3.2 TCK against OpenJPA
+# using DB selected.
+#
+# Usage:
+# ./run-tck32.sh # Run full TCK against postgres:16
+# DB_VERSION=18 ./run-tck32.sh # Run full TCK against postgres:18
+# DB_TYPE=mysql ./run-tck32.sh # Run full TCK against mysql:8.4.8
+# DB_HOST=myhost:5432 ./run-tck32.sh # Custom DB host
+# OPENJPA_VERSION=4.2.0-SNAPSHOT ./run-tck32.sh # Custom OpenJPA version
+#
+# Prerequisites:
+# - OpenJPA must be built and installed in local Maven repo
+# (run 'mvn install -DskipTests' from the project root)
+# - Java 17+ and Maven 3.x
+#
+
+set -e
+
+# Check required commands
+MISSING=""
+for cmd in java mvn curl unzip grep sed; do
+ if ! command -v "$cmd" &>/dev/null; then
+ MISSING="${MISSING} - ${cmd}\n"
+ fi
+done
+if [[ -n "$MISSING" ]]; then
+ echo "ERROR: The following required commands are not available:"
+ echo -e "$MISSING"
+ echo "Please install them before running this script."
+ exit 1
+fi
+
+stopAll() {
+ for profile in ${!FULL_DB_LIST[@]}; do
+ echo "Stopping dockerized ${profile}"
+ mvn -N -Ptest-${profile}-docker -f ${PROJECT_ROOT} -Ddocker.stopNamePattern=${profile:0:8}* docker:stop -Ddocker.showLogs
+ done
+}
+
+stopAll
+
+TCK_URL="https://download.eclipse.org/jakartaee/persistence/${TCK_BASE}/jakarta-persistence-tck-${TCK_VERSION}.zip"
+TCK_DIR="${SCRIPT_ROOT}/target/tck32"
+TCK_ZIP="${TCK_DIR}/jakarta-persistence-tck-${TCK_VERSION}.zip"
+TCK_HOME="${TCK_DIR}/persistence-tck"
+OPENJPA_VERSION="${OPENJPA_VERSION:-4.2.0-SNAPSHOT}"
+START_DOCKER=
+
+if [[ -z "${DB_HOST}" ]]; then
+ START_DOCKER=1
+fi
+
+DB_TYPE="${DB_TYPE:-postgresql}"
+DB_HOST="${DB_HOST:-localhost:5555}"
+DB_USER="${DB_USER:-tcktest}"
+DB_PASSWORD="${DB_PASSWORD:-tcktest}"
+DB_NAME="${DB_NAME:-tcktest}"
+DB_URL=""
+declare -a JPROPS=()
+
+DB_HOST_ONLY="${DB_HOST%%:*}"
+DB_PORT="${DB_HOST##*:}"
+
+TCK_DB_TYPE="${FULL_DB_LIST[${DB_TYPE}]}"
+
+setProps() {
+ local ver="${VERSIONS[${DB_TYPE}]}"
+ if [[ -n "${DB_VERSION}" ]]; then
+ ver="${DB_VERSION}"
+ fi
+ if [[ -n "${VERSIONS[${DB_TYPE}]}" ]]; then
+ JPROPS+=("-D${DB_TYPE}.server.version=${ver}")
+ fi
+
+ case ${DB_TYPE} in
+ mysql)
+ DB_URL="jdbc:mysql://${DB_HOST}/${DB_NAME}?useSSL=false&allowPublicKeyRetrieval=true&transformedBitIsBoolean=true"
+ ;;
+ postgresql)
+ DB_URL="jdbc:postgresql://${DB_HOST}/${DB_NAME}"
+ ;;
+ mssql)
+ DB_NAME=""
+ DB_URL="jdbc:sqlserver://${DB_HOST};sendTimeAsDatetime=false;trustServerCertificate=true"
+ ;;
+ oracle)
+ JPROPS+=("-Dopenjpa.oracle.SID=${DB_NAME}")
+ DB_NAME="XE"
+ DB_URL="jdbc:oracle:thin:@${DB_HOST}:${DB_NAME}"
+ ;;
+ esac
+ JPROPS+=("-Ddocker.external.${DB_TYPE}.port=${DB_PORT}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.dbname=${DB_NAME}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.username=${DB_USER}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.password=${DB_PASSWORD}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.url=${DB_URL}")
+}
+
+setProps
+
+if [[ -n "${START_DOCKER}" ]]; then
+ echo "Starting dockerized ${DB_TYPE}"
+ mvn -N -f ${PROJECT_ROOT} -Ptest-${DB_TYPE}-docker "${JPROPS[@]}" docker:start -Ddocker.showLogs
+fi
+
+GF_VERSION="${GF_VERSION:-8.0.0}"
+
+echo "=== JPA ${TCK_BASE} TCK Runner for OpenJPA ==="
+echo "OpenJPA version: ${OPENJPA_VERSION}"
+echo "TCK version: ${TCK_VERSION}"
+echo "GlassFish: ${GF_VERSION}"
+echo "Database: ${DB_TYPE} (${DB_HOST}/${DB_NAME})"
+echo ""
+
+# Step 1: Download TCK if not present
+mkdir -p "${TCK_DIR}"
+if [[ ! -f "${TCK_ZIP}" ]]; then
+ echo "Downloading JPA ${TCK_BASE} TCK..."
+ curl -sL -o "${TCK_ZIP}" "${TCK_URL}"
+ echo "Downloaded."
+else
+ echo "TCK zip already present, skipping download."
+fi
+
+# Step 2: Extract TCK
+if [[ ! -d "${TCK_HOME}" ]]; then
+ echo "Extracting TCK..."
+ cd "${TCK_DIR}" && unzip -q "${TCK_ZIP}"
+ echo "Extracted."
+else
+ echo "TCK already extracted, skipping."
+fi
+
+# Step 3: Install TCK artifacts into local Maven repo
+echo "Installing TCK artifacts..."
+cd "${TCK_HOME}/artifacts" && bash artifact-install.sh "${TCK_VERSION}"
+echo "TCK artifacts installed."
+
+# Step 4: Patch TCK pom.xml to add OpenJPA profile (if not already patched)
+TCK_POM="${TCK_HOME}/bin/pom.xml"
+if [[ -z "$(grep '<id>openjpa</id>' "${TCK_POM}")" ]]; then
+ echo "Adding OpenJPA profile to TCK pom.xml..."
+
+ sed '/<\/profiles>/,$d' "${TCK_POM}" > temp
+ cat "${SCRIPT_ROOT}/tck32-openjpa-profile.xml" >> temp
+ sed '/<\/profiles>/,$!d' "${TCK_POM}" >> temp
+ mv temp "${TCK_POM}"
+
+ echo "OpenJPA profile added."
+else
+ echo "OpenJPA profile already present in TCK pom.xml."
+fi
+
+echo ""
+echo "=== Preparing ${DB_TYPE} database ==="
Review Comment:
I'll perform clean-up (missing DB tables are being created by maven and dropped by `docker:remove` ...)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3691085395
##########
openjpa-kernel/src/main/jjtree/org/apache/openjpa/kernel/jpql/JPQL.jjt:
##########
@@ -195,6 +215,8 @@ TOKEN [ IGNORE_CASE ]: /* functions returning strings */
| < TRIM: "TRIM" >
| < LOWER: "LOWER" >
| < UPPER: "UPPER" >
+ | < RIGHT: "RIGHT" >
+ | < REPLACE: "REPLACE" >
Review Comment:
Added replace as a viable path_component
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801454207
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/common/apps/CompUser.java:
##########
@@ -66,6 +67,9 @@ public class CompUser {
@Enumerated
@Basic
private CreditRating creditRating;
+
+ @Version
Review Comment:
I'm fixing the two follow-ups right away: `groupBy`/`orderBy` still have the same PK-column issue, and the now-unguarded null version field. Will push shortly with tests.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3802364743
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EnumValueHandler.java:
##########
@@ -116,8 +219,26 @@ public Object toDataStoreValue(ValueMapping vm, Object val, JDBCStore store) {
public Object toObjectValue(ValueMapping vm, Object val) {
if (val == null)
return null;
- if (_ordinal)
- return _vals[((Number) val).intValue()];
- return Enum.valueOf(vm.getType(), (String) val);
+ if (_useEnumeratedValue) {
+ initEnumeratedValueField(vm.getType());
+ Enum<?> result = _dbToEnum.get(val);
+ if (result == null && val instanceof Number) {
+ result = _dbToEnum.get(((Number) val).intValue());
+ }
+ if (result == null) {
+ result = _dbToEnum.get(val.toString());
+ }
+ return result;
Review Comment:
@rzo1 I'm afraid this question is for you
Additionally I wonder why `ENUMERATED_VALUE_CLASS` inited with function call? `EnumeratedValue.class` looks easier
and later on `if (f.isAnnotationPresent(ENUMERATED_VALUE_CLASS)) {` might throw NPE ...
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801405861
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/common/apps/CompUser.java:
##########
@@ -66,6 +67,9 @@ public class CompUser {
@Enumerated
@Basic
private CreditRating creditRating;
+
+ @Version
Review Comment:
Fixed in 08d79ebab.
The entity change was fine — adding `CompVerUser` just removed a coincidence that was hiding a pre-existing bug in the `VERSION()` implementation. `VersionVal.appendTo()`/`length()` delegated to `_path`, and for a bare identification variable `PCPath` falls back to `getPrimaryKeyColumns()`, so `version(u) = :version` compiled to `t0.userid = ?` bound with the version value. The old `CompUser "Seetha"` happened to have `userid == version == 1`, so it matched by accident; `CompVerUser` draws a later sequence block (`userid = 101`), which exposed it.
Both methods now use `getColumns(state)` (the version columns), which is what `selectColumns()` already did — that's why the projection form always worked. Predicate SQL is now `WHERE (t0.name = ? AND t0.version = ?)`, otherwise byte-identical. `TestEJBQLFunction` is 65/65 and a full reactor run is clean (4061 tests, 0 failures).
Two related things I left alone, happy to file separately: `VersionVal.groupBy`/`orderBy` have the same defect, so `GROUP BY`/`ORDER BY VERSION(u)` still emit the PK column; and `getColumns()` dereferences `getVersionFieldMapping()` unguarded, so `VERSION(u)` on an unversioned entity would now NPE instead of silently comparing the PK — `initialize()` would be the place for a `UserException`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3802023338
##########
.github/workflows/ci.yml:
##########
@@ -14,26 +14,37 @@
# specific language governing permissions and limitations under the License.
#
name: Java CI
-on: [push]
+on:
+ push:
+ branches: [master]
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
env:
MAVEN_OPTS: -Dmaven.artifact.threads=256 -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
jobs:
build:
runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ java: [17, 21]
+ profile: [test-derby, test-h2]
+ name: build (Java ${{ matrix.java }}, ${{ matrix.profile }})
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v7
- name: Setup Java JDK
- uses: actions/setup-java@v4
+ uses: actions/setup-java@v5
with:
distribution: 'zulu'
- java-version: 11
+ java-version: ${{ matrix.java }}
- name: 'Cache Maven packages'
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: ~/.m2
key: 'cache'
Review Comment:
Hopefully fixed with [ef99961](https://github.com/apache/openjpa/pull/144/commits/ef99961d4519f4a476808a2dd3f962bba1399d66)
I'll wait for the build and check
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3781877927
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
Review Comment:
Unfortunately it will break everything :(
Oracle docker creates lots of files as `root` thus `mvn clean` will fail is such case
I've tried `${project.basedir}/jdbc_oradata` and `${project.basedir}/openjpa-xmlstore/jdbc_oradata` but this makes `apache-rat` very unhappy ....
Any ideas are much appreciated :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4476884358
@solomax , I tested against pg-18 and it passed.
I 've got some issues with mysql 9.4+ (lts) because LIBRARY became a reserved word and we got some tests where Library is the name of entity. Digging the code, found that DBDictionary has a namingRules field, but I couldn't find where exactly it is used. Adding LIBRARY to MySQLDictionary reservedWords list didn't do much. Can you give me some directions?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3526043808
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
> CURRENT_TIME is already being skipped for oracle, isn't it?
Somehow I'm getting following stacktrace at this test:
https://github.com/apache/openjpa/blob/master/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypesafeCriteria.java#L1681
```
[ERROR] org.apache.openjpa.persistence.criteria.TestTypesafeCriteria.testBasicLocalTime -- Time elapsed: 2668 s <<< ERROR!
<openjpa-4.2.0-SNAPSHOT-r159e12bM fatal store error> org.apache.openjpa.persistence.OptimisticLockException: Unable to obtain an object lock on "null".
at org.apache.openjpa.jdbc.sql.DBDictionary.narrow(DBDictionary.java:5521)
at org.apache.openjpa.jdbc.sql.DBDictionary.newStoreException(DBDictionary.java:5499)
at org.apache.openjpa.jdbc.sql.SQLExceptions.getStore(SQLExceptions.java:134)
at org.apache.openjpa.jdbc.sql.SQLExceptions.getStore(SQLExceptions.java:115)
at org.apache.openjpa.jdbc.sql.SQLExceptions.getStore(SQLExceptions.java:67)
at org.apache.openjpa.jdbc.kernel.SelectResultObjectProvider.handleCheckedException(SelectResultObjectProvider.java:162)
at org.apache.openjpa.kernel.QueryImpl$PackingResultObjectProvider.handleCheckedException(QueryImpl.java:2258)
at org.apache.openjpa.lib.rop.EagerResultList.<init>(EagerResultList.java:42)
at org.apache.openjpa.kernel.QueryImpl.toResult(QueryImpl.java:1347)
at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:1075)
at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:909)
at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:840)
at org.apache.openjpa.kernel.DelegatingQuery.execute(DelegatingQuery.java:601)
at org.apache.openjpa.persistence.QueryImpl.execute(QueryImpl.java:302)
at org.apache.openjpa.persistence.QueryImpl.getResultList(QueryImpl.java:319)
at org.apache.openjpa.persistence.QueryImpl.getSingleResult(QueryImpl.java:349)
at org.apache.openjpa.persistence.criteria.TestTypesafeCriteria.testBasicLocalTime(TestTypesafeCriteria.java:1699)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at junit.framework.TestCase.runTest(TestCase.java:177)
at junit.framework.TestCase.runBare(TestCase.java:142)
at org.apache.openjpa.persistence.criteria.AbstractCriteriaTestCase.runBare(AbstractCriteriaTestCase.java:360)
at junit.framework.TestResult$1.protect(TestResult.java:122)
at junit.framework.TestResult.runProtected(TestResult.java:142)
at junit.framework.TestResult.run(TestResult.java:125)
at junit.framework.TestCase.run(TestCase.java:130)
at junit.framework.TestSuite.runTest(TestSuite.java:241)
at junit.framework.TestSuite.run(TestSuite.java:236)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:90)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:316)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:240)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:214)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:155)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: ORA-00904: "CURRENT_TIME": invalid identifier
{prepstmnt 238780535 SELECT CURRENT_TIME FROM CR_ODR t0 WHERE (t0.id = ?)} [code=904, state=42000]
at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:219)
at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:203)
at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator$LoggingConnection$LoggingPreparedStatement.executeQuery(LoggingConnectionDecorator.java:1171)
at org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:300)
at org.apache.openjpa.jdbc.kernel.JDBCStoreManager$CancelPreparedStatement.executeQuery(JDBCStoreManager.java:1877)
at org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:290)
at org.apache.openjpa.jdbc.sql.SelectImpl.executeQuery(SelectImpl.java:534)
at org.apache.openjpa.jdbc.sql.SelectImpl.execute(SelectImpl.java:459)
at org.apache.openjpa.jdbc.sql.SelectImpl.execute(SelectImpl.java:426)
at org.apache.openjpa.jdbc.sql.LogicalUnion$UnionSelect.execute(LogicalUnion.java:477)
at org.apache.openjpa.jdbc.sql.LogicalUnion.execute(LogicalUnion.java:259)
at org.apache.openjpa.jdbc.sql.LogicalUnion.execute(LogicalUnion.java:248)
at org.apache.openjpa.jdbc.kernel.SelectResultObjectProvider.open(SelectResultObjectProvider.java:95)
at org.apache.openjpa.kernel.QueryImpl$PackingResultObjectProvider.open(QueryImpl.java:2210)
at org.apache.openjpa.lib.rop.EagerResultList.<init>(EagerResultList.java:36)
... 31 more
NestedThrowables:
java.sql.SQLSyntaxErrorException: ORA-00904: "CURRENT_TIME": invalid identifier
at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:509)
at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:461)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1104)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:550)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:268)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:655)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:270)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:91)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:807)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:983)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1168)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3666)
at oracle.jdbc.driver.T4CPreparedStatement.executeInternal(T4CPreparedStatement.java:1426)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3713)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1167)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:123)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:123)
at org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:302)
at org.apache.openjpa.lib.jdbc.JDBCEventConnectionDecorator$EventPreparedStatement.executeQuery(JDBCEventConnectionDecorator.java:250)
at org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:300)
at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator$LoggingConnection$LoggingPreparedStatement.executeQuery(LoggingConnectionDecorator.java:1169)
at org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:300)
at org.apache.openjpa.jdbc.kernel.JDBCStoreManager$CancelPreparedStatement.executeQuery(JDBCStoreManager.java:1877)
at org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:290)
at org.apache.openjpa.jdbc.sql.SelectImpl.executeQuery(SelectImpl.java:534)
at org.apache.openjpa.jdbc.sql.SelectImpl.execute(SelectImpl.java:459)
at org.apache.openjpa.jdbc.sql.SelectImpl.execute(SelectImpl.java:426)
at org.apache.openjpa.jdbc.sql.LogicalUnion$UnionSelect.execute(LogicalUnion.java:477)
at org.apache.openjpa.jdbc.sql.LogicalUnion.execute(LogicalUnion.java:259)
at org.apache.openjpa.jdbc.sql.LogicalUnion.execute(LogicalUnion.java:248)
at org.apache.openjpa.jdbc.kernel.SelectResultObjectProvider.open(SelectResultObjectProvider.java:95)
at org.apache.openjpa.kernel.QueryImpl$PackingResultObjectProvider.open(QueryImpl.java:2210)
at org.apache.openjpa.lib.rop.EagerResultList.<init>(EagerResultList.java:36)
at org.apache.openjpa.kernel.QueryImpl.toResult(QueryImpl.java:1347)
at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:1075)
at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:909)
at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:840)
at org.apache.openjpa.kernel.DelegatingQuery.execute(DelegatingQuery.java:601)
at org.apache.openjpa.persistence.QueryImpl.execute(QueryImpl.java:302)
at org.apache.openjpa.persistence.QueryImpl.getResultList(QueryImpl.java:319)
at org.apache.openjpa.persistence.QueryImpl.getSingleResult(QueryImpl.java:349)
at org.apache.openjpa.persistence.criteria.TestTypesafeCriteria.testBasicLocalTime(TestTypesafeCriteria.java:1699)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at junit.framework.TestCase.runTest(TestCase.java:177)
at junit.framework.TestCase.runBare(TestCase.java:142)
at org.apache.openjpa.persistence.criteria.AbstractCriteriaTestCase.runBare(AbstractCriteriaTestCase.java:360)
at junit.framework.TestResult$1.protect(TestResult.java:122)
at junit.framework.TestResult.runProtected(TestResult.java:142)
at junit.framework.TestResult.run(TestResult.java:125)
at junit.framework.TestCase.run(TestCase.java:130)
at junit.framework.TestSuite.runTest(TestSuite.java:241)
at junit.framework.TestSuite.run(TestSuite.java:236)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:90)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:316)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:240)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:214)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:155)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
Caused by: Error : 904, Position : 7, Sql = SELECT CURRENT_TIME FROM CR_ODR t0 WHERE (t0.id = :1 ), OriginalSql = SELECT CURRENT_TIME FROM CR_ODR t0 WHERE (t0.id = ?), Error Msg = ORA-00904: "CURRENT_TIME": invalid identifier
at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:513)
... 63 more
```
I'll definitely will re-run `org.apache.openjpa.persistence.criteria.TestTypesafeCriteria` but I need to wait for the current run to finish ... :(((
the current status is:
`[INFO] Running org.apache.openjpa.persistence.property.TestEMProperties`
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3525149822
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
@solomax , hopefully fixed issues with RIGHT (my fault on 3.1) and CEILING (didn't fathom oracle did not have support) . CURRENT_TIME is already being skipped for oracle, isn't it?
I'll tackle EXCEPT issue on Wednesday. If you can test oracle on the tests affected by the changes, I'll be pleased.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3584921709
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
superb :)))
Another issue:
Test: https://github.com/apache/openjpa/blob/OPENJPA-2940/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestJava8TimeTypes.java#L144
Result:
```
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.761 s <<< FAILURE! -- in org.apache.openjpa.persistence.simple.TestJava8TimeTypes
[ERROR] org.apache.openjpa.persistence.simple.TestJava8TimeTypes.testMaxOffsetTime -- Time elapsed: 0.701 s <<< FAILURE!
junit.framework.AssertionFailedError: expected:<20:57:15+07:00> but was:<05:12:34+07:00>
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3549752634
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
hmmmm
for whatever reason `postgres-16` now fails this test:
```
[ERROR] Tests run: 6, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 7.068 s <<< FAILURE! -- in org.apache.openjpa.persistence.lockmgr.TestPessimisticLocks
[ERROR] org.apache.openjpa.persistence.lockmgr.TestPessimisticLocks.testQueryAfterFindWithPessimisticLocks -- Time elapsed: 0.158 s <<< FAILURE!
junit.framework.AssertionFailedError: Unexpected find succeeded. Should throw a PessimisticLockException.
at junit.framework.Assert.fail(Assert.java:57)
at junit.framework.TestCase.fail(TestCase.java:223)
at org.apache.openjpa.persistence.lockmgr.TestPessimisticLocks.testQueryAfterFindWithPessimisticLocks(TestPessimisticLocks.java:303)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3426859590
##########
.github/dependabot.yml:
##########
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+version: 2
Review Comment:
fair :) will be removed :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3804649084
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypesafeCriteria.java:
##########
@@ -1781,5 +1789,168 @@ public void testIdClass() {
assertEquivalence(cq, jpql);
}
+
+ public void testLeft() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where left(p.name, 4) = 'John'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.left(c.get("name"), 4), "John"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testRight() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where RIGHT(p.name, 3) = 'Doe'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.right(c.get("name"), 3), "Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testReplace() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ String jpql = "select p from Person p where REPLACE(p.name, 'ohn', 'ack') = 'Jack Fitzgerald Doe'";
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.replace(c.get("name"), "ohn", "ack"), "Jack Fitzgerald Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ /**
+ * JPA 3.2 Criteria UNION must execute end-to-end and produce the
+ * same SQL as the JPQL UNION form. We don't compare row counts
+ * because TestTypesafeCriteria shares a static EMF with other test
+ * classes and we don't want to seed shared tables.
+ */
+ public void testCriteriaUnion() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 30));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.equal(r2.get("name"), "Ugo"));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> union = cb.union(q1, q2);
+ assertNotNull(em.createQuery(union).getResultList());
+ }
+
+ public void testCriteriaUnionAll() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 25));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.gt(r2.<Integer>get("age"), 30));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> unionAll = cb.unionAll(q1, q2);
+ assertNotNull(em.createQuery(unionAll).getResultList());
+ }
+
+ public void testCriteriaExcept() {
Review Comment:
I guess `CriteriaSelectImpl` need some hint on `dbDictionary == Oracle` (so `MINUS` can be used instead of `EXCEPT`)
But so far I can't find the way to pass it ....
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3800727910
##########
.gitignore:
##########
@@ -11,3 +11,11 @@ nbactions*.xml
.checkstyle
.vscode
+.claude
+CLAUDE.md
+tck-dev
+docker-compose.yml
+pgdata
+openjpa-xmlstore/jdbc*
Review Comment:
should be fixed with 3bf1ccee8
BTW weird enough `jdbc:derby:` seems to be "gitignored" even without correspondent line in `.gitignore` file ...
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3802493033
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EnumValueHandler.java:
##########
@@ -116,8 +219,26 @@ public Object toDataStoreValue(ValueMapping vm, Object val, JDBCStore store) {
public Object toObjectValue(ValueMapping vm, Object val) {
if (val == null)
return null;
- if (_ordinal)
- return _vals[((Number) val).intValue()];
- return Enum.valueOf(vm.getType(), (String) val);
+ if (_useEnumeratedValue) {
+ initEnumeratedValueField(vm.getType());
+ Enum<?> result = _dbToEnum.get(val);
+ if (result == null && val instanceof Number) {
+ result = _dbToEnum.get(((Number) val).intValue());
+ }
+ if (result == null) {
+ result = _dbToEnum.get(val.toString());
+ }
+ return result;
Review Comment:
I'll have a look at this comment.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801454207
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/common/apps/CompUser.java:
##########
@@ -66,6 +67,9 @@ public class CompUser {
@Enumerated
@Basic
private CreditRating creditRating;
+
+ @Version
Review Comment:
Will do — and I'm fixing the two follow-ups right away: `groupBy`/`orderBy` still have the same PK-column issue, and the now-unguarded null version field. Will push shortly with tests, and file the JIRA to go with it.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3802017024
##########
.github/workflows/ci.yml:
##########
@@ -14,26 +14,37 @@
# specific language governing permissions and limitations under the License.
#
name: Java CI
-on: [push]
+on:
+ push:
+ branches: [master]
Review Comment:
@rmannibucau the list of active branches contains just this one
Could you please name `maintenance branches`?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5323300896
> My GitHub webapp doesn't open all of the comments anymore (lol) - seems a bit broken. So where are we atm?
Hello @rzo1,
same here :)) I have to manually click "load more" to load everything :))
regarding status: we have 7 unresolved `(high)` comments from @rmannibucau and I would like to get them fixed/reviewed :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rmannibucau (via GitHub)" <gi...@apache.org>.
rmannibucau commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801752542
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
Review Comment:
maybe stupid but why dont we use test container ? should enable to make all the setup mess programmatically.
mktemp can be an option but setup starts to be weirdish, sudo is not an option IMHO
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801808325
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
Review Comment:
Perhaps it would be worth to migrate to testcontainers some day, but I think it can be treated as follow-up? Already pretty huge here.
Agree with sudo not being an option.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3802444880
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
Review Comment:
I can try to switch to `https://hub.docker.com/r/gvenzl/oracle-xe`, docker image from Oracle was used to have some sort of "official" Oracle DB ....
(but I believe this is not a blocker)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3811764663
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestTimeoutException.java:
##########
@@ -97,6 +99,37 @@ public void testQueryTimeOutExceptionWhileQueryingWithLocksOnAlreadyLockedEntiti
}
}
+ public void testLockTimeOutExceptionWhileQueryingWithLocksOnAlreadyLockedEntitiesOption() {
Review Comment:
same story with `TestPessimisticLockException` :(((
I think migrating to JUnit5 with `@Timeout` annotations might be good idea :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3557858005
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
Million thanks @rzo1 !
makes sense! :) I'll try this code and will report back :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3557725124
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
Investigated this one - it's reproducible without OpenJPA and it's not a driver/binding issue (`sendTimeAsDatetime=false` is already set on the connection URL and doesn't help).
The `{t '01:32:21'}` in those queries is the JDBC/ODBC escape literal coming straight from the JPQL. OpenJPA inlines it verbatim into the SQL (`Lit.appendTo`), and SQL Server types the ODBC `{t}` escape as legacy `datetime`, not `time`:
```sql
SELECT SQL_VARIANT_PROPERTY({t '01:32:21'}, 'BaseType') -- returns: datetime
```
Since SQL Server has **no implicit conversion between `time` and `datetime`**, comparing it against our `EXTRACT(TIME ...)` translation (`CAST(... AS TIME)`) raises error 402:
```sql
SELECT 1 WHERE CAST({ts '2005-03-21 01:32:21'} AS TIME) = {t '01:32:21'}
-- Msg 402: The data types time and datetime are incompatible in the equal to operator.
```
Only `{t}` is affected — `{d}` and `{ts}` also map to `datetime`, but `date`/`datetime` comparisons have an implicit conversion, so they work.
**Fix (verified against SQL Server 2022):** rewrite the time escape to a typed literal on MSSQL: `{t '01:32:21'}` → `CAST('01:32:21' AS TIME)`. Both failing queries then behave exactly as the tests expect:
```sql
WHERE CAST({ts '2005-03-21 01:32:21'} AS TIME) = CAST('01:32:21' AS TIME) -- matches
WHERE CAST(CONVERT(TIME, GETDATE()) AS TIME) = CAST('01:32:20' AS TIME) -- 0 rows
```
The only place these escapes enter the SQL is `Lit.appendTo` in `openjpa-jdbc`, so the fix might be something like that in the dictionary:
```java
// Lit.java — delegate instead of raw passthrough
} else if (parseType == Literal.TYPE_DATE || parseType == Literal.TYPE_TIME ||
parseType == Literal.TYPE_TIMESTAMP) {
lstate.sqlValue = new Raw(ctx.store.getDBDictionar
.toJDBCEscapedDateTimeLiteral(_val.toString(), parseType));
}
```
```java
// DBDictionary — default passthrough
public String toJDBCEscapedDateTimeLiteral(String escape, int parseType) {
return escape;
}
```
```java
// SQLServerDictionary — unwrap only the time escape
@Override
public String toJDBCEscapedDateTimeLiteral(String escape, int parseType) {
// SQL Server types the ODBC {t '...'} escape as Dss),
// which has no implicit conversion to TIME -> err
if (parseType == Literal.TYPE_TIME) {
int start = escape.indexOf('\'');
int end = escape.lastIndexOf('\'');
if (start >= 0 && end > start) {
return "CAST(" + escape.substring(start, end + 1) + " AS TIME)";
}
}
return escape;
}
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3687193289
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerFactory.java:
##########
@@ -161,4 +162,41 @@ Broker newBroker(String user, String pass, boolean managed,
* This method is invoked AFTER a BrokerFactory has been instantiated.
*/
void postCreationCallback();
+
+ /**
+ * Creates the database schema and tables required by the persistence
+ * unit. Implements the {@code create} action of the JPA 3.2
+ * {@link jakarta.persistence.SchemaManager} contract.
+ *
+ * @since 4.2.0
+ */
+ void createPersistenceStructure(boolean createSchemas);
+
+ /**
+ * Drops the database schema and tables managed by the persistence
+ * unit. Implements the {@code drop} action of the JPA 3.2
+ * {@link jakarta.persistence.SchemaManager} contract.
+ *
+ * @since 4.2.0
+ */
+ void dropPersistenceStrucuture(boolean dropSchemas);
Review Comment:
Fixed typos.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rmannibucau (via GitHub)" <gi...@apache.org>.
rmannibucau commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3682713652
##########
.github/workflows/ci.yml:
##########
@@ -14,26 +14,37 @@
# specific language governing permissions and limitations under the License.
#
name: Java CI
-on: [push]
+on:
+ push:
+ branches: [master]
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
env:
MAVEN_OPTS: -Dmaven.artifact.threads=256 -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
jobs:
build:
runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ java: [17, 21]
+ profile: [test-derby, test-h2]
+ name: build (Java ${{ matrix.java }}, ${{ matrix.profile }})
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v7
Review Comment:
note for future work: should be pinned and perms of the workflow should be tuned
##########
openjpa-integration/daytrader/pom.xml:
##########
@@ -94,6 +94,7 @@
<goals>
<goal>unpack</goal>
</goals>
+ <?m2e ignore?>
Review Comment:
really needed? it is out of maven schema anyway, no comment flavor?
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Replace.java:
##########
@@ -0,0 +1,76 @@
+/*
+ * 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.kernel.exps;
+
+import org.apache.openjpa.kernel.StoreContext;
+
+/**
+ * Take the replaces part of the given string
+ *
+ * @author Abe White
+ * @author Paulo Cristovão Filho
+ */
+class Replace
+ extends Val {
+
+
+ private static final long serialVersionUID = 1L;
+ private final Val _orig;
+ private final Val _patt;
+ private final Val _repl;
+
+ /**
+ * Constructor. Provides values of replacement.
+ */
+ public Replace(Val orig, Val pattern, Val replacement) {
+ _orig = orig;
+ _patt = pattern;
+ _repl = replacement;
+ }
+
+ @Override
+ public Class getType() {
+ return String.class;
+ }
+
+ @Override
+ public void setImplicitType(Class type) {
+ }
+
+ @Override
+ protected Object eval(Object candidate, Object orig,
+ StoreContext ctx, Object[] params) {
+ String str = _orig.eval(candidate, orig, ctx, params).toString();
+ String patt = _patt.eval(candidate, orig, ctx, params).toString();
+ String repl = _repl.eval(candidate, orig, ctx, params).toString();
Review Comment:
**(high)** This `while (str.indexOf(patt) != -1)` loop never terminates when the replacement contains the pattern (e.g. `REPLACE(x, 'a', 'aa')`) or when the pattern is empty, and it diverges from SQL REPLACE semantics which is a single pass: SQL `REPLACE('aaa','aa','a')` yields `'aa'` while this loop yields `'a'`. A single `str.replace(patt, repl)` already replaces all occurrences and matches datastore behavior - can we drop the loop?
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerFactory.java:
##########
@@ -161,4 +162,41 @@ Broker newBroker(String user, String pass, boolean managed,
* This method is invoked AFTER a BrokerFactory has been instantiated.
*/
void postCreationCallback();
+
+ /**
+ * Creates the database schema and tables required by the persistence
+ * unit. Implements the {@code create} action of the JPA 3.2
+ * {@link jakarta.persistence.SchemaManager} contract.
+ *
+ * @since 4.2.0
+ */
+ void createPersistenceStructure(boolean createSchemas);
+
+ /**
+ * Drops the database schema and tables managed by the persistence
+ * unit. Implements the {@code drop} action of the JPA 3.2
+ * {@link jakarta.persistence.SchemaManager} contract.
+ *
+ * @since 4.2.0
+ */
+ void dropPersistenceStrucuture(boolean dropSchemas);
Review Comment:
**(high)** Typos in two brand-new public API method names: `dropPersistenceStrucuture` (line 182) and `validatePersistenceStruture` (line 191). Last chance to fix them to `dropPersistenceStructure`/`validatePersistenceStructure` before they freeze; the typos are replicated in DelegatingBrokerFactory, AbstractBrokerFactory, JDBCBrokerFactory and SchemaManagerImpl.
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Left.java:
##########
@@ -0,0 +1,68 @@
+/*
+ * 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.kernel.exps;
+
+import org.apache.openjpa.kernel.StoreContext;
+
+/**
+ * Take the left part of a string.
+ *
+ * @author Abe White
+ * @author Paulo Cristovão Filho
+ */
+class Left
+ extends Val {
+
+
+ private static final long serialVersionUID = 1L;
+ private final Val _val;
+ private final Val _len;
+
+ /**
+ * Constructor. Provide substring and length of the left part that must be kept.
+ */
+ public Left(Val val, Val len) {
+ _val = val;
+ _len = len;
+ }
+
+ @Override
+ public Class getType() {
+ return String.class;
+ }
+
+ @Override
+ public void setImplicitType(Class type) {
+ }
+
+ @Override
+ protected Object eval(Object candidate, Object orig, StoreContext ctx, Object[] params) {
+ Object str = _val.eval(candidate, orig, ctx, params);
+ Object arg = _len.eval(candidate, orig, ctx, params);
+ return str.toString().substring(0, ((Number) arg).intValue());
Review Comment:
**(high)** `substring(0, len)` throws StringIndexOutOfBoundsException when the requested length exceeds the string length (SQL LEFT just returns the whole string) - Right.java:62 handles exactly this case, so Left should mirror it. Negative lengths and a null value are also unguarded.
##########
openjpa-kernel/src/main/jjtree/org/apache/openjpa/kernel/jpql/JPQL.jjt:
##########
@@ -195,6 +215,8 @@ TOKEN [ IGNORE_CASE ]: /* functions returning strings */
| < TRIM: "TRIM" >
| < LOWER: "LOWER" >
| < UPPER: "UPPER" >
+ | < RIGHT: "RIGHT" >
+ | < REPLACE: "REPLACE" >
Review Comment:
**(medium)** The new `REPLACE` token (and `INTEGER`/`LONG`/`FLOAT`/`DOUBLE` at lines 187-190) are not listed in `path_component()`, unlike CAST/ID/VERSION etc. An existing field named `replace` or `integer` (e.g. `o.replace`) no longer parses - can they be added to `path_component()` like the others?
##########
openjpa-kernel/src/main/jjtree/org/apache/openjpa/kernel/jpql/JPQL.jjt:
##########
@@ -1031,6 +1112,11 @@ void entity_type_comp() : { }
)
}
+void entity_id_or_version_comp() : { }
Review Comment:
**(medium)** `entity_id_or_version_comp()` only allows `ID(x)`/`VERSION(x)` compared with `=`/`<>` against an input parameter. Spec-legal forms like `ID(e) = 5`, `VERSION(e) >= :v` or `ID(a) = ID(b)` do not parse - intentional first step, or should these functions be reachable from the general comparison/arithmetic productions?
##########
openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java:
##########
@@ -1475,8 +1501,118 @@ public void setConverter(Class converter) {
_converter = converter;
_converterExtMethod = null;
_converterFactMethod = null;
+ _converterInstance = null;
+ _converterDbType = null;
}
-
+
+ /**
+ * Get (or create) a cached instance of the converter class.
+ */
+ private Object getConverterInstance() throws Exception {
Review Comment:
**(medium)** The converter instance is now created once and cached in a non-volatile field without synchronization; FieldMetaData is shared across brokers/threads, so this is unsafe publication and a behavior change (previously a new converter instance per conversion, now one shared instance that must be thread-safe). Consider thread-safe caching and documenting that AttributeConverters are treated as shared/stateless.
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java:
##########
@@ -790,6 +815,16 @@ public Value getKey(Value val) {
public Value getObjectId(Value val) {
return new GetObjectId((Val) val);
}
+
+ @Override
+ public Value getNativeObjectId(Value val) {
+ return new GetObjectId((Val) val);
Review Comment:
**(medium)** `getNativeObjectId` returns the same `GetObjectId` as `getObjectId`, which evaluates to the internal ObjectId wrapper (e.g. LongId), not the raw PK value - so an in-memory `ID(e) = :id` comparison against the plain key may never match; should it unwrap like the JDBC side? Similarly `setOperands`/`setOperationType` and `nullPrecedence` appear consumed only by the JDBC store, so in-memory execution of UNION/INTERSECT/EXCEPT or NULLS FIRST/LAST silently produces wrong results - should the in-memory path reject or implement them?
##########
openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java:
##########
@@ -703,6 +715,61 @@ public OpenJPAConfigurationImpl(boolean derivations, boolean loadGlobals) {
loadGlobals();
}
+ @Override
+ public void fromProperties(Map map) {
+ if (map != null) {
+ // Detect if any JPA schema generation property was explicitly
+ // provided. When set, JPA schema gen takes priority over
+ // OpenJPA's SynchronizeMappings.
+ for (Object key : map.keySet()) {
+ if (key instanceof String
+ && ((String) key).startsWith(
+ "jakarta.persistence.schema-generation.")) {
+ _schemaGenerationExplicit = true;
+ break;
+ }
+ }
+ // Extract Writer/Reader objects before they hit StringValue
+ // (which would just call toString() and lose them).
+ extractSchemaGenObjects(map,
+ "jakarta.persistence.schema-generation.scripts.create-target",
+ java.io.Writer.class, true);
+ extractSchemaGenObjects(map,
+ "jakarta.persistence.schema-generation.scripts.drop-target",
+ java.io.Writer.class, false);
+ extractSchemaGenObjects(map,
+ "jakarta.persistence.schema-generation.create-script-source",
+ java.io.Reader.class, true);
+ extractSchemaGenObjects(map,
+ "jakarta.persistence.schema-generation.drop-script-source",
+ java.io.Reader.class, false);
+ }
+ super.fromProperties(map);
+ }
+
+ private void extractSchemaGenObjects(Map map, String key,
+ Class<?> expectedType, boolean isCreate) {
+ Object val = map.get(key);
+ if (expectedType.isInstance(val)) {
+ // Store the object and remove from map so StringValue
+ // doesn't mangle it
+ map.remove(key);
Review Comment:
**(medium)** `extractSchemaGenObjects` calls `map.remove(key)` on the caller-supplied properties map - this mutates user configuration and throws UnsupportedOperationException for unmodifiable maps (e.g. `Map.of(...)` passed to `createEntityManagerFactory`). Can the Writer/Reader values be captured without mutating the input?
##########
openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java:
##########
@@ -330,4 +332,27 @@ public static Object getManagedInstance(Object o) {
else
return o;
}
+
+ /**
+ * Returns the entity class for the given object, unwrapping any
+ * runtime-generated pcsubclass proxy. For runtime-enhanced entities,
+ * {@code obj.getClass()} returns the generated subclass (e.g.
+ * {@code Order$pcsubclass}), but for {@code equals()}/{@code hashCode()}
+ * comparisons the original entity class should be used.
+ *
+ * @param obj the object whose entity class to determine
+ * @return the original entity class (superclass of pcsubclass), or
+ * the object's actual class if it is not a pcsubclass
+ * @since 4.2.0
+ */
+ public static Class<?> getEntityClass(Object obj) {
+ if (obj == null) {
+ return null;
+ }
+ Class<?> cls = obj.getClass();
+ if (cls.getName().contains("$pcsubclass")) {
Review Comment:
**(low)** `cls.getName().contains("$pcsubclass")` is a fragile string match and only strips one level of subclassing; consider reusing the naming constant/utility that generates pcsubclass names, or walking superclasses until the name no longer matches.
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaTool.java:
##########
@@ -479,71 +509,140 @@ protected void deleteTableContents()
Collection<Table> tables = new LinkedHashSet<>();
for (Schema schema : schemas) {
Table[] ts = schema.getTables();
- for (Table t : ts) {
- tables.add(t);
- }
+ Collections.addAll(tables, ts);
}
Table[] tableArray = tables.toArray(new Table[tables.size()]);
Connection conn = _ds.getConnection();
+ // Truncate is a best-effort operation: the repo SchemaGroup may
+ // declare tables the dialect never actually created (e.g.
+ // OPENJPA_SEQUENCE_TABLE on dialects that prefer native sequences,
+ // or tables in other schemas). Log missing-table errors instead of
+ // aborting.
+ boolean savedIgnore = _ignoreErrs;
+ _ignoreErrs = true;
try {
String[] sql = _conf.getDBDictionaryInstance()
.getDeleteTableContentsSQL(tableArray, conn);
if (!executeSQL(sql)) {
_log.warn(_loc.get("delete-table-contents"));
}
} finally {
+ _ignoreErrs = savedIgnore;
closeConnection(conn);
}
}
- protected void executeScript() throws SQLException {
- if (_scriptToExecute == null) {
- _log.warn(_loc.get("generating-execute-script-not-defined"));
- return;
+ private BufferedReader getScriptReader() throws IOException {
+ BufferedReader reader = null;
+ if (_scriptReader != null) {
+ reader = (_scriptReader instanceof BufferedReader br) ? br : new BufferedReader(_scriptReader);
+ } else {
+ URL url = null;
+ // Try file: URI or absolute path first
+ if (_scriptToExecute.startsWith("file:")) {
+ try {
+ url = new URI(_scriptToExecute).toURL();
+ } catch (Exception e) {
+ // fall through to classloader lookup
+ }
+ } else {
+ File f = new File(_scriptToExecute);
+ if (f.isAbsolute() && f.exists()) {
+ url = f.toURI().toURL();
+ }
+ }
+ // Fall back to classloader resource lookup
+ if (url == null) {
+ url = _conf.getClassResolverInstance()
+ .getClassLoader(SchemaTool.class, null)
+ .getResource(_scriptToExecute);
+ }
+ if (url == null) {
+ _log.error(_loc.get("generating-execute-script-not-found", _scriptToExecute));
+ return null;
+ }
+ _log.info(_loc.get("generating-execute-script", _scriptToExecute));
+ reader = new BufferedReader(new InputStreamReader(url.openStream()));
}
+ return reader;
+ }
- URL url = AccessController.doPrivileged(
- J2DoPrivHelper.getResourceAction(_conf.getClassResolverInstance().
- getClassLoader(SchemaTool.class, null), _scriptToExecute));
-
- if (url == null) {
- _log.error(_loc.get("generating-execute-script-not-found", _scriptToExecute));
+ protected void executeScript() throws SQLException {
+ if (_scriptReader == null && StringUtil.isBlank(_scriptToExecute)) {
+ _log.warn(_loc.get("generating-execute-script-not-defined"));
return;
}
- _log.info(_loc.get("generating-execute-script", _scriptToExecute));
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new InputStreamReader(url.openStream()));
- String sql;
+ try (BufferedReader reader = getScriptReader()) {
+ if (reader == null) {
+ return;
+ }
+ String line;
List<String> script = new ArrayList<>();
- while ((sql = reader.readLine()) != null) {
- sql = sql.trim();
- if (sql.startsWith("--") || sql.startsWith("/*") || sql.startsWith("//")) {
+ StringBuilder stmt = new StringBuilder();
+ AtomicBoolean insideMultilineComments = new AtomicBoolean(false);
+ Function<String, String> stripComments = (str) -> {
Review Comment:
**(high)** The `stripComments` lambda looks inverted: for `INSERT INTO t VALUES (1) /* note */;` it does `str.substring(cutStart, multiEndIdx)`, keeping the comment body and discarding the SQL around it, and it leaves `insideMultilineComments` true so every following line of the script is blanked. There is also an infinite loop when a line contains `*/` without `/*` outside a comment (e.g. `'*/'` in a literal): the loop never modifies `str` and never breaks. Should this be `str.substring(0, cutStart) + str.substring(multiEndIdx + 2)`?
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/InstantVersionStrategy.java:
##########
@@ -0,0 +1,64 @@
+/*
+ * 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.meta.strats;
+
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.meta.JavaTypes;
+
+/**
+ * Uses an {@link Instant} for optimistic versioning.
+ *
+ * @since 4.2.0
+ */
+public class InstantVersionStrategy
+ extends ColumnVersionStrategy {
+
+ private static final long serialVersionUID = 1L;
+ public static final String ALIAS = "version-instant";
+
+ @Override
+ public String getAlias() {
+ return ALIAS;
+ }
+
+ @Override
+ protected int getJavaType() {
+ return JavaTypes.INSTANT;
+ }
+
+ @Override
+ protected Object nextVersion(Object version) {
+ return Instant.now();
+ }
+
+ @Override
+ public Map<Column, String> getBulkUpdateValues() {
+ Column[] cols = vers.getColumns();
+ Map<Column, String> map = new HashMap<>(cols.length);
+ Object d = nextVersion(null);
+ for (Column col : cols) {
+ map.put(col, d.toString());
Review Comment:
**(high)** `getBulkUpdateValues()` returns `d.toString()`, but DBDictionary appends a String map value raw into the UPDATE SQL (that mechanism exists so NumberVersionStrategy can emit `version + 1`). So bulk updates on an Instant-versioned entity produce `SET VERSCOL = 2026-07-30T10:15:30.123Z` - unquoted, invalid SQL. Returning the Instant itself (like TimestampVersionStrategy returns the Timestamp) would let it be parameterized. Same in LocalDateTimeVersionStrategy.java:60.
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Left.java:
##########
@@ -0,0 +1,164 @@
+/*
+ * 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.JavaSQLTypes;
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.jdbc.sql.SQLBuffer;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.kernel.Filters;
+import org.apache.openjpa.kernel.exps.ExpressionVisitor;
+import org.apache.openjpa.meta.ClassMetaData;
+
+/**
+ * Take the left part of a string.
+ *
+ * @author Abe White
+ * @author Paulo Cristovão Filho
+ * @since 4.2.0
+ */
+public class Left
+ extends AbstractVal {
+
+
+ private static final long serialVersionUID = 1L;
+ private final Val _val1;
+ private final Val _val2;
+ private ClassMetaData _meta = null;
+
+ /**
+ * Constructor. Provide the string and length to operate on
+ */
+ public Left(Val val1, Val val2) {
+ _val1 = val1;
+ _val2 = val2;
+ }
+
+ public Val getVal1() {
+ return _val1;
+ }
+
+ public Val getVal2() {
+ return _val2;
+ }
+
+ @Override
+ public ClassMetaData getMetaData() {
+ return _meta;
+ }
+
+ @Override
+ public void setMetaData(ClassMetaData meta) {
+ _meta = meta;
+ }
+
+ @Override
+ public Class getType() {
+ return String.class;
+ }
+
+ @Override
+ public void setImplicitType(Class type) {
+ }
+
+ @Override
+ public ExpState initialize(Select sel, ExpContext ctx, int flags) {
+ ExpState s1 = _val1.initialize(sel, ctx, 0);
+ ExpState s2 = _val2.initialize(sel, ctx, 0);
+ return new BinaryOpExpState(sel.and(s1.joins, s2.joins), s1, s2);
+ }
+
+ @Override
+ public void select(Select sel, ExpContext ctx, ExpState state,
+ boolean pks) {
+ sel.select(newSQLBuffer(sel, ctx, state), this);
+ }
+
+ @Override
+ public void selectColumns(Select sel, ExpContext ctx, ExpState state,
+ boolean pks) {
+ BinaryOpExpState bstate = (BinaryOpExpState) state;
+ _val1.selectColumns(sel, ctx, bstate.state1, true);
+ _val2.selectColumns(sel, ctx, bstate.state2, true);
+ }
+
+ @Override
+ public void groupBy(Select sel, ExpContext ctx, ExpState state) {
+ sel.groupBy(newSQLBuffer(sel, ctx, state));
+ }
+
+ @Override
+ public void orderBy(Select sel, ExpContext ctx, ExpState state,
+ boolean asc) {
+ sel.orderBy(newSQLBuffer(sel, ctx, state), asc, false, getSelectAs());
+ }
+
+ private SQLBuffer newSQLBuffer(Select sel, ExpContext ctx, ExpState state) {
+ calculateValue(sel, ctx, state, null, null);
+ SQLBuffer buf = new SQLBuffer(ctx.store.getDBDictionary());
+ appendTo(sel, ctx, state, buf, 0);
+ return buf;
+ }
+
+ @Override
+ public Object load(ExpContext ctx, ExpState state, Result res)
+ throws SQLException {
+ return Filters.convert(res.getObject(this,
+ JavaSQLTypes.JDBC_DEFAULT, null), getType());
+ }
+
+ @Override
+ public void calculateValue(Select sel, ExpContext ctx, ExpState state,
+ Val other, ExpState otherState) {
+ BinaryOpExpState bstate = (BinaryOpExpState) state;
+ _val1.calculateValue(sel, ctx, bstate.state1, null, null);
+ _val2.calculateValue(sel, ctx, bstate.state2, null, null);
+ }
+
+ @Override
+ public int length(Select sel, ExpContext ctx, ExpState state) {
+ return 1;
+ }
+
+ @Override
+ public void appendTo(Select sel, ExpContext ctx, ExpState state,
+ SQLBuffer sql, int index) {
+ BinaryOpExpState bstate = (BinaryOpExpState) state;
+ FilterValue str = new FilterValueImpl(sel, ctx, bstate.state1, _val1);
+ FilterValue len = new FilterValueImpl(sel, ctx, bstate.state2, _val2);
+
+ ctx.store.getDBDictionary().left(sql, str, len);
+ }
+
+ @Override
+ public void acceptVisit(ExpressionVisitor visitor) {
+ visitor.enter(this);
+ _val1.acceptVisit(visitor);
+ _val2.acceptVisit(visitor);
+ visitor.exit(this);
+ }
+
+ @Override
+ public int getId() {
+ return Val.SUBSTRING_VAL;
Review Comment:
**(high)** `getId()` returns `Val.SUBSTRING_VAL`, but `JDBCStoreQuery.evaluate()` dispatches SUBSTRING_VAL to `handleSubstringVal`, which casts to `Substring` and unpacks an `Args` - with a Left (or Right/Replace, same at Right.java:161 and Replace.java:162) this throws ClassCastException as soon as the in-memory evaluation path is hit. Either these need their own ids plus handlers, or an id that falls into the UnsupportedException default.
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java:
##########
@@ -665,13 +671,14 @@ private Table getTable(FieldMapping[] fields, Table table) {
/**
* Return the table for the field if the given table hasn't been set
* yet, or if the tables match. If the field uses a different table,
- * returns INVALID. Also returns INVALID if field is dependent.
+ * returns INVALID.
+ *
+ * Note: cascade delete fields are no longer treated as INVALID because
+ * JPA bulk delete operations do not cascade to related entities
+ * (JPA spec section 4.10). The remaining column/table checks are
+ * sufficient to detect multi-table mappings that prevent bulk SQL DELETE.
*/
private Table getTable(FieldMapping fm, Table table) {
Review Comment:
**(medium)** Removing the `getCascadeDelete() != CASCADE_NONE -> INVALID` guard means bulk DELETE no longer falls back to loading instances for entities with cascading/dependent fields. JPA 4.10 (no cascade on bulk delete) is fine, but this strategy also handled dependent-field cleanup: join-table / element-collection rows previously removed via the in-memory fallback can now be left orphaned unless the DB has ON DELETE CASCADE. Was that trade-off verified for the element-collection case?
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCBrokerFactory.java:
##########
@@ -140,13 +167,47 @@ protected BrokerImpl newBrokerImpl(String user, String pass) {
}
}
+ @Override
+ public void createPersistenceStructure(boolean createSchemas) {
+ JDBCConfiguration conf = (JDBCConfiguration) getConfiguration();
+ Broker broker = super.newBrokerImpl(conf.getConnectionUserName(), conf.getConnectionPassword());
Review Comment:
**(medium)** `createPersistenceStructure`, `dropPersistenceStrucuture`, `validatePersistenceStruture` and `truncateData` each create a Broker via `super.newBrokerImpl(...)` that is only used for `getClassLoader()` and never closed - a broker (and its resources) leaked per call. Can the classloader be obtained without instantiating a broker?
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaTool.java:
##########
@@ -101,6 +103,21 @@ public class SchemaTool {
protected static final Localizer _loc = Localizer.forPackage(SchemaTool.class);
+ // Tables dropped by script execution during JPA schema generation.
+ // Only active when SpecCompliantSchemaGeneration is enabled (TCK mode).
+ // Prevents buildSchema/add from re-creating tables that were explicitly
+ // dropped by schema gen scripts within the same schema generation flow.
+ private static final java.util.Set<String> _droppedTables =
Review Comment:
**(medium)** `_droppedTables` is JVM-global static mutable state and `clearDroppedTables()` is invoked from JDBCBrokerFactory whenever any EMF with schema-gen properties spins up - with two persistence units initializing concurrently (common in app servers) one EMF wipes the other's in-flight tracking. Matching also uses `toUpperCase()` without `Locale.ROOT` (here, line 1239 and 1519-1529) and compares a full identifier against a name regex-stripped from raw DDL, so schema-qualified or quoted names will not match. Could this state live on the configuration instead?
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/TypecastAsString.java:
##########
@@ -0,0 +1,91 @@
+/*
+ * 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.kernel.exps;
+
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+
+import org.apache.openjpa.kernel.StoreContext;
+
+/**
+ * Casts a given value as string
+ *
+ */
+class TypecastAsString extends Val {
+ private static final long serialVersionUID = 1L;
+ private final Val _val;
+
+ /**
+ * Constructor. Provide target field and the value.
+ */
+ public TypecastAsString(Val val) {
+ _val = val;
+ }
+
+ @Override
+ public Class getType() {
+ return String.class;
+ }
+
+ @Override
+ public void setImplicitType(Class type) {
+ }
+
+ @Override
+ protected Object eval(Object candidate, Object orig,
+ StoreContext ctx, Object[] params) {
+
+ Object r = _val.eval(candidate, orig, ctx, params);
+ Class<?> clazz = r.getClass();
+ if (Time.class.isAssignableFrom(clazz)) {
+ return ((Time) r).toLocalTime().format(DateTimeFormatter.ISO_TIME);
+ } else if (Timestamp.class.isAssignableFrom(clazz)) {
+ return ((Timestamp) r).toLocalDateTime().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
+ } else if (LocalDateTime.class.isAssignableFrom(clazz)) {
+ return ((LocalDateTime) r).toLocalTime().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
Review Comment:
**(high)** The LocalDateTime branch converts to `toLocalTime()` then formats with `ISO_LOCAL_DATE_TIME`, which throws UnsupportedTemporalTypeException because LocalTime has no date fields - should this just be `((LocalDateTime) r).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)`?
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/InstantVersionStrategy.java:
##########
@@ -0,0 +1,64 @@
+/*
+ * 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.meta.strats;
+
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.meta.JavaTypes;
+
+/**
+ * Uses an {@link Instant} for optimistic versioning.
+ *
+ * @since 4.2.0
+ */
+public class InstantVersionStrategy
+ extends ColumnVersionStrategy {
+
+ private static final long serialVersionUID = 1L;
+ public static final String ALIAS = "version-instant";
+
+ @Override
+ public String getAlias() {
+ return ALIAS;
+ }
+
+ @Override
+ protected int getJavaType() {
+ return JavaTypes.INSTANT;
+ }
+
+ @Override
+ protected Object nextVersion(Object version) {
+ return Instant.now();
Review Comment:
**(medium)** `Instant.now()` carries micro/nano precision on modern JVMs; if the version column's precision is lower (MySQL TIMESTAMP defaults, Oracle DATE) the value read back differs from the in-memory version, producing spurious optimistic-lock failures on the next flush - the same reason TimestampVersionStrategy deliberately uses millisecond granularity. Should this truncate to a precision known to survive the DB round-trip?
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedValueHandler.java:
##########
@@ -242,6 +320,35 @@ protected int toObjectValue1(OpenJPAStateManager em, ValueMapping vm,
ValueMapping vm1 = fm.getValueMapping();
OpenJPAStateManager em1 = null;
+ // JPA 2.4.1.3 ex2b: non-@Embeddable @IdClass field —
+ // reconstruct POJO from FK column values via reflection
+ if (!(fm.getStrategy() instanceof Embeddable)) {
+ List<Column> mic = fm.getValueInfo().getMapsIdColumns();
+ if (mic != null && !mic.isEmpty()) {
+ try {
+ Object idObj = fm.getDeclaredType()
+ .getDeclaredConstructor().newInstance();
+ List<java.lang.reflect.Field> df =
+ getInstanceFields(fm.getDeclaredType(), mic.size());
+ int ci = 0;
+ for (java.lang.reflect.Field f : df) {
+ Object cv;
+ if (val instanceof Object[])
+ cv = ((Object[]) val)[idx + ci];
+ else
+ cv = val;
+ f.set(idObj, cv);
+ ci++;
+ }
+ em.store(fm.getIndex(), idObj);
+ } catch (Exception ex) {
Review Comment:
**(medium)** The IdClass reconstruction/extraction paths `catch (Exception)` and silently continue (here the field stays null; in `toDataStoreValue` at line 227 the PK columns get nulls written). Swallowing exceptions around primary-key values risks silently persisting/loading corrupt identities - at minimum a warn log, arguably a StoreException. Also `getInstanceFields` (line 448) maps IdClass fields to columns by `getDeclaredFields()` order, which the JVM does not guarantee - matching by name would be safer.
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/TypecastAsNumber.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.kernel.exps;
+
+import org.apache.openjpa.kernel.StoreContext;
+
+/**
+ * Extract the part value of a temporal type
+ *
+ */
+class TypecastAsNumber extends Val {
+ private static final long serialVersionUID = 1L;
+ private final Class<? extends Number> _targetType;
+ private final Val _val;
+
+ /**
+ * Constructor. Provide target field and the value.
+ */
+ public TypecastAsNumber(Val val, Class<? extends Number> target) {
+ _val = val;
+ _targetType = target;
+ }
+
+ @Override
+ public Class getType() {
+ if (_targetType == Integer.class) {
+ return int.class;
+ } else if (_targetType == Long.class) {
+ return long.class;
+ } else if (_targetType == Float.class) {
+ return float.class;
+ } else if (_targetType == Double.class) {
+ return double.class;
+ } else {
+ return _targetType;
+ }
+ }
+
+ @Override
+ public void setImplicitType(Class type) {
+ }
+
+ @Override
+ protected Object eval(Object candidate, Object orig,
+ StoreContext ctx, Object[] params) {
+
+ Object r = _val.eval(candidate, orig, ctx, params);
+ Class<?> clazz = r.getClass();
+ if (_targetType == Integer.class) {
+ if (r instanceof String s) {
+ return Integer.valueOf(s);
+ } else if (clazz.isAssignableFrom(Number.class)) {
Review Comment:
**(high)** The `clazz.isAssignableFrom(Number.class)` checks are inverted (should be `Number.class.isAssignableFrom(clazz)` or simply `r instanceof Number`), so casting any numeric value to INTEGER/LONG/FLOAT/DOUBLE in memory always falls through to `throw new IllegalArgumentException()`. Same at lines 74, 80 and 86; also worth giving the exception a message and handling `r == null`. The class javadoc "Extract the part value of a temporal type" also looks copy-pasted from ExtractDateTimePart.
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/TypecastAsString.java:
##########
@@ -0,0 +1,91 @@
+/*
+ * 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.kernel.exps;
+
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+
+import org.apache.openjpa.kernel.StoreContext;
+
+/**
+ * Casts a given value as string
+ *
+ */
+class TypecastAsString extends Val {
+ private static final long serialVersionUID = 1L;
+ private final Val _val;
+
+ /**
+ * Constructor. Provide target field and the value.
+ */
+ public TypecastAsString(Val val) {
+ _val = val;
+ }
+
+ @Override
+ public Class getType() {
+ return String.class;
+ }
+
+ @Override
+ public void setImplicitType(Class type) {
+ }
+
+ @Override
+ protected Object eval(Object candidate, Object orig,
+ StoreContext ctx, Object[] params) {
+
+ Object r = _val.eval(candidate, orig, ctx, params);
+ Class<?> clazz = r.getClass();
+ if (Time.class.isAssignableFrom(clazz)) {
+ return ((Time) r).toLocalTime().format(DateTimeFormatter.ISO_TIME);
+ } else if (Timestamp.class.isAssignableFrom(clazz)) {
+ return ((Timestamp) r).toLocalDateTime().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
+ } else if (LocalDateTime.class.isAssignableFrom(clazz)) {
+ return ((LocalDateTime) r).toLocalTime().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
+ } else if (LocalTime.class.isAssignableFrom(clazz)) {
+ return ((LocalTime) r).format(DateTimeFormatter.ISO_LOCAL_TIME);
+ } else if (Instant.class.isAssignableFrom(clazz)) {
+ return LocalDateTime.ofInstant((Instant) r, ZoneId.systemDefault()).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
+ } else if (Date.class.isAssignableFrom(clazz)) {
+ return LocalDateTime.ofInstant(((Date) r).toInstant(), ZoneId.systemDefault()).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
Review Comment:
**(high)** `java.sql.Date.toInstant()` is specified to always throw UnsupportedOperationException, so this branch can never succeed; it also formats a date-only value as a date-time. Suggest `((java.sql.Date) r).toLocalDate().format(ISO_LOCAL_DATE)`; note plain `java.util.Date` and `String` inputs currently fall through to the bare IllegalArgumentException at the end.
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java:
##########
@@ -1015,9 +1013,25 @@ private boolean isInMemory(int operation) {
// involved in this query, we have to execute in memory or flush
boolean inMem = !_storeQuery.supportsDataStoreExecution()
|| _collection != null;
- if (!inMem && (!_ignoreChanges || operation != OP_SELECT)
- && _broker.isActive() && isAccessPathDirty()) {
- int flush = _fc.getFlushBeforeQueries();
+ int flush = _fc.getFlushBeforeQueries();
+
+ // Per JPA spec, FlushModeType.AUTO (FLUSH_TRUE) requires that
+ // pending changes are visible to queries. The access path check
+ // may miss dirty entities reachable via navigation (e.g.,
+ // o.customer.spouse), so when FLUSH_TRUE is set we check for
+ // ANY dirty objects rather than only those in the access path.
+ boolean dirty;
Review Comment:
**(medium)** With FLUSH_TRUE (default FlushModeType.AUTO) this now flushes before every query as soon as anything in the context is dirty, and the `flush == FLUSH_TRUE` addition at line 1033 also overrides the IgnoreChanges setting. That defeats the access-path optimization and can be a real perf regression in write-heavy transactions - can the broadened check be limited to types related to the query access path, or guarded by a compatibility flag?
##########
openjpa-kernel/src/main/jjtree/org/apache/openjpa/kernel/jpql/JPQL.jjt:
##########
Review Comment:
**(medium)** `identification_variable()` only accepts `<IDENTIFIER>`, so every newly introduced token (ID, VERSION, RIGHT, ON, NULLS, FIRST, LAST, CAST, STRING, UNION, INTERSECT, EXCEPT, TREAT, ...) can no longer be used as an identification variable or result alias. Existing queries like `SELECT e.id AS id ... ORDER BY id` or aliases named `first`/`on` now fail to parse - a backward-compat regression worth documenting or mitigating with soft keywords.
(re line 1560, outside the diff hunks)
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java:
##########
@@ -477,7 +823,160 @@ public boolean isLoaded(Object entity, String attribute) {
return (OpenJPAPersistenceUtil.isManagedBy(this, entity) &&
(OpenJPAPersistenceUtil.isLoaded(entity, attribute) == LoadState.LOADED));
}
-
+
+ @Override
+ public <E> boolean isLoaded(E entity, Attribute<? super E, ?> attribute) {
+ return isLoaded(entity, attribute.getName());
+ }
+
+ @Override
+ public SchemaManager getSchemaManager() {
+ if (!this.isOpen()) {
+ throw new IllegalStateException("EntityManagerFactory is closed.");
+ }
+ return new SchemaManagerImpl(_factory);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <R> R callInTransaction(Function<EntityManager, R> work) {
+ EntityManager em = createEntityManager();
+ boolean startedTransaction = false;
+ boolean jtaTransaction = getTransactionType() == PersistenceUnitTransactionType.JTA;
+ Broker broker = em.unwrap(Broker.class);
+ try {
+ if (jtaTransaction) {
+ if (!broker.syncWithManagedTransaction()) {
+ broker.begin();
+ startedTransaction = true;
+ }
+ } else {
+ em.getTransaction().begin();
+ startedTransaction = true;
+ }
+ R result = work.apply(em);
+ if (startedTransaction) {
+ if (jtaTransaction) {
+ broker.commit();
+ } else {
+ em.getTransaction().commit();
+ }
+ }
+ // For unenhanced (runtime-subclassed) entities, the user's function
+ // may return an original POJO that was passed to persist().
+ // Entities loaded via find() on other EMs are subclass instances,
+ // causing getClass() mismatches in equals(). To ensure consistent
+ // class identity, re-find managed entities from the database so that
+ // the returned instance is a subclass (matching what find() returns).
+ if (result != null && em.contains(result)) {
Review Comment:
**(high)** This post-commit "re-find" block (`em.clear()` + `em.find()` when the returned value is a managed entity) issues an extra DB round-trip outside any transaction on every `callInTransaction` returning an entity, silently discards the persistence context, swallows all exceptions, and returns a different instance than the user's function returned. Nothing in the spec requires this; it looks like a workaround for the unenhanced-subclass case. Can it be dropped or at least gated to runtime-unenhanced types only?
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Ceiling.java:
##########
@@ -55,7 +59,13 @@ protected Class getType(Class c) {
@Override
protected String getOperator() {
- return "CEILING";
+ return operator;
+ }
+
+ @Override
+ public void appendTo(Select sel, ExpContext ctx, ExpState state, SQLBuffer sql, int index) {
Review Comment:
**(low)** `appendTo` mutates the instance field `operator` before delegating to `super.appendTo` (same pattern in NaturalLogarithm.java:49). Compiled query plans are cached and shared, so this is a data race on shared state; passing the dictionary function down locally (e.g. an `appendTo(..., String operator)` overload in UnaryOp) would keep the Val immutable.
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java:
##########
@@ -789,18 +793,42 @@ private void preFlushPC(ValueMetaData vmd, Object obj, boolean logical, OpCallba
return; // allow but ignore
}
+ // If the object is not manageable (e.g. unenhanced original reference)
+ // but its class is a known entity type, treat it as detached. This
+ // handles the case where an entity was persisted in a prior transaction
+ // and the original (unenhanced) reference is used in a relationship
+ // with cascade=NONE (e.g. @JoinColumn(insertable=false, updatable=false)).
Review Comment:
**(medium)** This early-return treats any unmanageable instance of a known entity type as detached without verifying it was ever persisted, so a truly transient unenhanced object referenced without cascade now passes the check and fails later (or silently persists a broken FK). Line 824 also adds `_broker.isDetached(obj, true)`, a DB round-trip inside the flush path for every manageable object without a state manager. Can both paths at least verify a non-null/assigned identity before assuming detached?
##########
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,
Review Comment:
**(low)** This `toDataStoreValue` override is line-for-line identical to `GetObjectId.toDataStoreValue` - only `load()` differs. Can the duplicate be removed so fixes to the base class do not need applying twice?
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ConverterElementHandler.java:
##########
@@ -0,0 +1,142 @@
+/*
+ * 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.meta.strats;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.openjpa.jdbc.identifier.DBIdentifier;
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.meta.ValueMapping;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.ColumnIO;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.meta.JavaTypes;
+import org.apache.openjpa.util.MetaDataException;
+
+/**
+ * ValueHandler for element collections that use a JPA
+ * {@code AttributeConverter}. Unlike {@link ConverterValueHandler}, this
+ * handler actively converts values because element collection elements
+ * are not routed through the externalization path.
+ *
+ * @since 4.2.0
+ */
+public class ConverterElementHandler extends AbstractValueHandler {
+
+ private static final long serialVersionUID = 1L;
+
+ private final Class<?> _converterClass;
+ private final Class<?> _dbType;
+ private transient Object _converterInstance;
+ private transient Method _toDbMethod;
+ private transient Method _toEntityMethod;
+
+ public ConverterElementHandler(Class<?> converterClass, Class<?> dbType) {
+ _converterClass = converterClass;
+ _dbType = dbType;
+ }
+
+ @Override
+ public Column[] map(ValueMapping vm, String name, ColumnIO io,
+ boolean adapt) {
+ DBDictionary dict = vm.getMappingRepository().getDBDictionary();
+ DBIdentifier colName = DBIdentifier.newColumn(name,
+ dict != null ? dict.delimitAll() : false);
+
+ Column col = new Column();
+ col.setIdentifier(colName);
+ col.setJavaType(JavaTypes.getTypeCode(_dbType));
+ return new Column[]{ col };
+ }
+
+ @Override
+ public Object toDataStoreValue(ValueMapping vm, Object val,
+ JDBCStore store) {
+ if (val == null) {
+ return null;
+ }
+ try {
+ ensureInitialized();
+ return _toDbMethod.invoke(_converterInstance, val);
+ } catch (InvocationTargetException ite) {
+ Throwable cause = ite.getTargetException();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ }
+ throw new MetaDataException(cause.toString()).setCause(cause);
+ } catch (Exception e) {
+ throw new MetaDataException(e.toString()).setCause(e);
+ }
+ }
+
+ @Override
+ public Object toObjectValue(ValueMapping vm, Object val) {
+ if (val == null) {
+ return null;
+ }
+ try {
+ ensureInitialized();
+ return _toEntityMethod.invoke(_converterInstance, val);
+ } catch (InvocationTargetException ite) {
+ Throwable cause = ite.getTargetException();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ }
+ throw new MetaDataException(cause.toString()).setCause(cause);
+ } catch (Exception e) {
+ throw new MetaDataException(e.toString()).setCause(e);
+ }
+ }
+
+ private void ensureInitialized() throws Exception {
+ if (_converterInstance == null) {
+ _converterInstance = _converterClass.getDeclaredConstructor()
Review Comment:
**(low)** Two questions: (1) the converter is instantiated via `getDeclaredConstructor().newInstance()`, bypassing CDI-managed converters (JPA allows converters as CDI beans with injection); (2) why reflection/`findMethod` instead of casting to `jakarta.persistence.AttributeConverter` and calling it directly? Note also the `val == null` short-circuits mean a converter mapping null to a default value is never consulted for nulls.
##########
openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java:
##########
@@ -1964,6 +2116,66 @@ public boolean resolve(int mode) {
return false;
}
+ /**
+ * Check if an auto-apply converter is registered for this field's
+ * declared type, and if so, set it as the converter.
+ */
+ private void applyAutoApplyConverter() {
+ Class declType = getDeclaredType();
+ if (declType == null || declType.isPrimitive())
+ return;
+ // Don't apply converters to ID fields, version fields, or
+ // relationship fields
+ if (isPrimaryKey() || isVersion())
+ return;
+ int tc = getDeclaredTypeCode();
+ if (tc == JavaTypes.PC
+ || tc == JavaTypes.COLLECTION || tc == JavaTypes.MAP)
+ return;
+ Class<?> converterCls = getRepository()
+ .getAutoApplyConverter(declType);
+ if (converterCls != null) {
+ setConverter(converterCls);
+ }
+ }
+
+ /**
+ * Propagate embedded converters from this field to the fields of the
+ * embedded class. Called when this field has @Converts annotations
+ * specifying converters for embedded attributes.
+ */
+ private void propagateEmbeddedConverters() {
Review Comment:
**(medium)** `propagateEmbeddedConverters()` sets the converter on the shared embeddable ClassMetaData. If two entities embed the same embeddable but only one declares `@Convert(attributeName=...)`, the override leaks to all other usages (last-resolved wins). Should the override only apply to the per-embedding `embeddedMeta` copy?
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java:
##########
@@ -1087,9 +1101,21 @@ public Number deleteInMemory(StoreQuery q, StoreQuery.Executor executor,
if (!(o instanceof Collection))
o = Collections.singleton(o);
+ // Per JPA spec (section 4.10), bulk delete operations do NOT
+ // cascade to related entities. Use a no-cascade callback to
+ // prevent OpenJPA from cascading the delete to related entities,
+ // which avoids FK ordering issues during flush.
+ OpCallbacks noCascade = (op, arg, sm) -> OpCallbacks.ACT_RUN;
int size = 0;
for (Iterator i = ((Collection) o).iterator(); i.hasNext(); size++)
- _broker.delete(i.next(), null);
+ _broker.delete(i.next(), noCascade);
+ // Flush the deletes to the database so that the bulk operation
+ // is visible immediately. Without this flush, em.clear() or
+ // subsequent find() calls in the same transaction would not
+ // see the deletes.
+ if (size > 0) {
+ _broker.flush();
Review Comment:
**(medium)** The new `_broker.flush()` after in-memory bulk delete (and update at line 1156) flushes the entire persistence context as a side effect of `executeUpdate()`, changing when unrelated pending changes hit the database (locks, triggers, constraint timing). Is flushing only the affected instances feasible, or is the full flush deliberate?
##########
openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java:
##########
@@ -2365,10 +2419,20 @@ public boolean is_systemListenersActivated() {
* Add the given system lifecycle listener.
*/
public void addSystemListener(Object listener) {
+ addSystemListener(listener, null);
+ }
+
+ /**
+ * Add a system lifecycle listener with an optional deduplication key.
+ * If a key is provided and a listener with the same key was already
+ * registered, the duplicate is silently skipped.
+ */
+ public void addSystemListener(Object listener, String key) {
+ if (key != null && !_systemListenerKeys.add(key)) {
Review Comment:
**(medium)** `_systemListenerKeys` is a plain HashSet mutated outside the `_locking` synchronized block, so concurrent `addSystemListener` calls can corrupt it; and since `removeSystemListener`/`clear()` never remove keys, a listener removed and re-registered with the same key is silently dropped forever. Suggest a concurrent set plus key removal on listener removal.
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java:
##########
@@ -3068,6 +3089,14 @@ public OpenJPAStateManager embed(Object obj, Object id,
}
sm.initialize(copy, state);
+
+ // JPA 3.2: for records, register the raw record instance →
+ // embedded copy mapping so that getStateManagerImpl can find
+ // the SM when the owner's enhanced field provides the raw record
+ if (obj != null && meta.isRecord()) {
+ ImplHelper._unenhancedInstanceMap.put(obj, copy);
Review Comment:
**(low)** Reaching into `ImplHelper._unenhancedInstanceMap` (a public mutable static field) directly is fragile - suggest a small `ImplHelper.registerUnenhancedInstance(obj, pc)` method instead of exposing the raw map.
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/AbstractExpressionBuilder.java:
##########
@@ -345,6 +351,54 @@ private boolean isMultiValuedTraversalAttempt(Path path, String field) {
return true;
}
+ /**
+ * Checks whether a class has an @Embeddable annotation via reflection.
+ * Uses annotation simple name to avoid compile-time dependency on
+ * jakarta.persistence.
+ */
+ private static boolean hasEmbeddableAnnotation(Class<?> type) {
Review Comment:
**(low)** `hasEmbeddableAnnotation` matches any annotation whose simple name is "Embeddable" (from any package) and misses embeddables declared only in orm.xml - would checking the repository metadata (e.g. `fmd.getEmbeddedMetaData()`) be more reliable than reflection on annotation names?
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBrokerFactory.java:
##########
@@ -259,4 +261,40 @@ public void postCreationCallback() {
throw translate(re);
}
}
+
+ @Override
+ public void createPersistenceStructure(boolean createSchemas) {
+ try {
+ _factory.createPersistenceStructure(createSchemas);
+ } catch (RuntimeException re) {
+ throw translate(re);
+ }
+ }
+
+ @Override
+ public void dropPersistenceStrucuture(boolean dropSchemas) {
+ try {
+ _factory.dropPersistenceStrucuture(dropSchemas);
+ } catch (RuntimeException re) {
+ throw translate(re);
+ }
+ }
+
+ @Override
+ public void validatePersistenceStruture() throws Exception {
Review Comment:
**(low)** Unlike its sibling delegating methods, `validatePersistenceStruture` only handles MetaDataException and converts to IllegalStateException instead of using `translate(re)`, so other RuntimeExceptions escape untranslated; the `(OpenJPAException) mde` cast is also redundant. Intentional asymmetry?
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MySQLDictionary.java:
##########
@@ -536,5 +559,55 @@ public void indexOf(SQLBuffer buf, FilterValue str, FilterValue find,
}
buf.append(")");
}
+
+ /**
+ * MySQL / MariaDB do not support ANSI SQL {@code NULLS FIRST} / {@code NULLS LAST}.
+ * Emulate via an auxiliary {@code <expr> IS NULL} sort key.
+ * <p>
+ * MySQL's default NULL ordering places NULLs before non-NULLs when sorting
+ * ASC and after non-NULLs when sorting DESC. When the requested precedence
+ * already matches that default, nothing extra is emitted. Otherwise the
+ * last order term {@code <expr> ASC|DESC} is rewritten to
+ * {@code <expr> IS NULL <sort>, <expr> ASC|DESC}.
+ */
+ @Override
+ public void appendNullsPrecedence(SQLBuffer ordering, int nullPrecedence) {
+ if (nullPrecedence != QueryExpressions.NULLS_FIRST
+ && nullPrecedence != QueryExpressions.NULLS_LAST) {
+ return;
+ }
+ String sql = ordering.getSQL();
+ int lastAsc = sql.lastIndexOf(" ASC");
+ int lastDesc = sql.lastIndexOf(" DESC");
+ boolean asc;
+ int termDirStart;
+ int termDirEnd;
+ if (lastAsc > lastDesc) {
+ asc = true;
+ termDirStart = lastAsc;
+ termDirEnd = lastAsc + " ASC".length();
+ } else if (lastDesc >= 0) {
+ asc = false;
+ termDirStart = lastDesc;
+ termDirEnd = lastDesc + " DESC".length();
+ } else {
+ return;
+ }
+ boolean defaultMatches =
+ (nullPrecedence == QueryExpressions.NULLS_FIRST && asc)
+ || (nullPrecedence == QueryExpressions.NULLS_LAST && !asc);
+ if (defaultMatches) {
+ return;
+ }
+ int termStart = Math.max(sql.lastIndexOf(", ", termDirStart), -1);
Review Comment:
**(high)** The NULLS FIRST/LAST emulation finds the last order term with `sql.lastIndexOf(", ", termDirStart)`, so any ORDER BY expression containing a comma (e.g. `COALESCE(t0.x, 0) DESC`) is split mid-argument-list and the rewrite produces corrupt SQL; duplicating the expression also duplicates `?` markers without duplicating bound parameters. The block is triplicated in MariaDBDictionary (~575) and SQLServerDictionary (~484) - can it be extracted to a shared helper operating on the order term before it is appended to the buffer instead of string-parsing it back out?
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java:
##########
@@ -170,23 +172,49 @@ public ResultObjectProvider executeQuery(StoreQuery q, Object[] params, Range ra
try {
DBDictionary dict = _store.getDBDictionary();
Connection conn = _store.getConnection();
+
+ // PostgreSQL requires auto-commit off for procedures
+ // that return REF_CURSOR (cursor lives within transaction)
+ boolean resetAutoCommit = false;
Review Comment:
**(high)** `resetAutoCommit` is assigned but never read: autocommit is switched off for REF_CURSOR procedures and never restored, so the connection returns to the pool with autoCommit=false (and the transaction opened for the cursor is neither committed nor rolled back here). Also if `prepareCall` or `rop.open()` throws, `conn` is never closed in the catch at line 220 - connection leak on the error path.
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCBrokerFactory.java:
##########
@@ -161,24 +222,121 @@ protected boolean synchronizeMappings(ClassLoader loader,
Configurations.configureInstance(tool, conf, props,
"SynchronizeMappings");
+ // Check for ExcludeTypes to skip specific entity classes during
+ // schema synchronization. Supports both the parenthesized form
+ // buildSchema(ExcludeTypes=...) and the standalone config property
+ // openjpa.jdbc.SyncMappingsExcludeTypes.
+ Set<String> excludeTypes = parseExcludeTypes(props);
+ if (excludeTypes.isEmpty()) {
+ String excludeProp = conf.getSyncMappingsExcludeTypes();
+ addSemicolonDelimited(excludeProp, excludeTypes);
+ }
+
// initialize the schema
for (Class<?> cls : classes) {
+ if (excludeTypes.contains(cls.getName())) {
+ continue;
+ }
try {
tool.run(cls);
} catch (IllegalArgumentException iae) {
throw new UserException(_loc.get("bad-synch-mappings",
action, Arrays.asList(MappingTool.ACTIONS)));
+ } catch (MetaDataException mde) {
+ // non-entity classes (DTOs, listeners, ID classes) may be
+ // listed in persistence.xml <class> elements; skip them
+ // during schema synchronization. Only skip if the class
+ // truly has no metadata — re-throw for managed types
+ // with invalid metadata (e.g. unsupported version type).
+ if (tool.getRepository().getMetaData(cls, null, false) != null) {
+ throw mde;
+ }
+ conf.getLog("openjpa.jdbc.Schema").warn(
+ "Skipping schema synchronization for non-managed class: "
+ + cls.getName());
}
}
tool.record();
+
+ // For excluded types, actively drop their tables if they exist
+ // in the database. This ensures tables from previous runs (before
+ // the type was excluded) don't persist and cause operations to
+ // succeed silently instead of throwing the expected RuntimeException.
+ if (!excludeTypes.isEmpty()) {
+ dropExcludedTypeTables(conf, repo, excludeTypes, loader);
+ }
+
return true; // todo: check?
}
protected boolean synchronizeMappings(ClassLoader loader) {
return synchronizeMappings(loader, (JDBCConfiguration) getConfiguration());
}
+ /**
+ * Drop tables for entity types that are excluded from schema
+ * synchronization. This ensures that tables left over from a previous
+ * run (before the type was excluded) are removed so that SQL operations
+ * against them will fail as expected.
+ */
+ private void dropExcludedTypeTables(JDBCConfiguration conf,
+ MappingRepository repo, Set<String> excludeTypes,
+ ClassLoader loader) {
+ Log log = conf.getLog("openjpa.jdbc.Schema");
+ DataSource ds = conf.getDataSource2(null);
+ for (String typeName : excludeTypes) {
+ try {
+ ClassLoader clsLoader = conf.getClassResolverInstance()
+ .getClassLoader(getClass(), loader);
+ Class<?> cls = Class.forName(typeName, true, clsLoader);
+
+ // Use the mapping repository to determine the table name
+ ClassMapping mapping = repo.getMapping(cls, clsLoader, false);
+ if (mapping == null || mapping.getTable() == null) {
+ continue;
+ }
+ String tableName =
+ mapping.getTable().getFullIdentifier().getName();
+
+ Connection conn = ds.getConnection();
+ try {
+ conn.setAutoCommit(true);
+ Statement stmt = conn.createStatement();
+ try {
+ stmt.executeUpdate("DROP TABLE " + tableName);
Review Comment:
**(high)** `dropExcludedTypeTables` issues a raw `"DROP TABLE " + tableName` bypassing the dictionary (no identifier quoting/`toDBName`, no CASCADE handling, will fail on Postgres with dependent constraints) and swallows every exception at trace level. More fundamentally, dropping a user table because its type was excluded from synchronization is destructive - an excluded type may be a table managed externally on purpose. Is this only here to make a specific test pass? It probably should not ship in production code.
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/BindVariableExpression.java:
##########
@@ -61,10 +65,55 @@ public ExpState initialize(Select sel, ExpContext ctx, Map contains) {
return _var.initialize(sel, ctx, 0);
}
+ /**
+ * Returns true if this variable was narrowed via TREAT to a subclass
+ * and needs a discriminator condition.
+ */
+ boolean hasTreatDiscriminator() {
+ ClassMetaData varMeta = _var.getMetaData();
+ if (varMeta instanceof ClassMapping varMapping) {
+ ClassMapping sup = varMapping;
+ while (sup.getMappedPCSuperclassMapping() != null) {
+ sup = sup.getMappedPCSuperclassMapping();
+ }
+ if (sup != varMapping) {
+ Discriminator disc = sup.getDiscriminator();
+ if (disc != null) {
+ Column[] cols = disc.getColumns();
+ Object discVal = varMapping.getDiscriminator() != null
+ ? varMapping.getDiscriminator().getValue() : null;
+ return cols != null && cols.length > 0 && discVal != null;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Appends the discriminator condition for TREAT-narrowed variables.
+ */
+ void appendTreatDiscriminator(Select sel, ExpState state, SQLBuffer buf) {
Review Comment:
**(medium)** `appendTreatDiscriminator` emits `disc = <treated class value>` only. Per JPA, `TREAT(x AS Middle)` must also match subtypes of Middle, so for a 3-level hierarchy this incorrectly filters out instances of Middle's subclasses - it should be an IN over the discriminator values of the treated class and all mapped subclasses. It also only handles `cols[0]` of the discriminator.
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java:
##########
@@ -1104,6 +1113,82 @@ public static Context getThreadLocalContext(Context lctx, Context cloneFrom) {
return null;
}
+ private ResultObjectProvider executeSetOperatorQuery(Executor ex,
Review Comment:
**(medium)** `executeSetOperatorQuery` receives `range` but never uses it, so `setFirstResult`/`setMaxResults` on a UNION/INTERSECT/EXCEPT query are silently ignored. Should the range at least be applied via RangeResultObjectProvider like the normal path does?
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/TypecastAsNumber.java:
##########
@@ -0,0 +1,197 @@
+/*
+ * 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.JavaSQLTypes;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.Joins;
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.jdbc.sql.SQLBuffer;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.kernel.Filters;
+import org.apache.openjpa.kernel.exps.ExpressionVisitor;
+import org.apache.openjpa.meta.ClassMetaData;
+
+/**
+ * Returns the given value as a number
+ *
+ * @since 4.2.0
+ */
+public class TypecastAsNumber extends AbstractVal {
+ private static final long serialVersionUID = 1L;
+ private final Val _val;
+ private final Class<? extends Number> _targetType;
+ private ClassMetaData _meta = null;
+
+ /**
+ * Constructor. Provide the date and the field to operate on.
+ */
+ public TypecastAsNumber(Val val, Class<? extends Number> target) {
+ _val = val;
+ _targetType = target;
+ }
+
+ public Val getVal() {
+ return _val;
+ }
+
+ @Override
+ public ClassMetaData getMetaData() {
+ return _meta;
+ }
+
+ @Override
+ public void setMetaData(ClassMetaData meta) {
+ _meta = meta;
+ }
+
+ @Override
+ public Class getType() {
+ if (_targetType == Integer.class) {
+ return int.class;
+ } else if (_targetType == Long.class) {
+ return long.class;
+ } else if (_targetType == Float.class) {
+ return float.class;
+ } else if (_targetType == Double.class) {
+ return double.class;
+ } else {
+ return _targetType;
+ }
+ }
+
+ @Override
+ public void setImplicitType(Class type) {
+ }
+
+ @Override
+ public ExpState initialize(Select sel, ExpContext ctx, int flags) {
+ ExpState valueState = _val.initialize(sel, ctx, 0);
+ return new ExtractTypecastToNumberExpState(valueState.joins, valueState);
+ }
+
+ /**
+ * Expression state.
+ */
+ private static class ExtractTypecastToNumberExpState extends ExpState {
+ public final ExpState valueState;
+
+ public ExtractTypecastToNumberExpState(Joins joins, ExpState valueState) {
+ super(joins);
+ this.valueState = valueState;
+ }
+ }
+
+ @Override
+ public void select(Select sel, ExpContext ctx, ExpState state, boolean pks) {
+ sel.select(newSQLBuffer(sel, ctx, state), this);
+ }
+
+ @Override
+ public void selectColumns(Select sel, ExpContext ctx, ExpState state, boolean pks) {
+ ExtractTypecastToNumberExpState etnstate = (ExtractTypecastToNumberExpState) state;
+ _val.selectColumns(sel, ctx, etnstate.valueState, true);
+ }
+
+ @Override
+ public void groupBy(Select sel, ExpContext ctx, ExpState state) {
+ sel.groupBy(newSQLBuffer(sel, ctx, state));
+ }
+
+ @Override
+ public void orderBy(Select sel, ExpContext ctx, ExpState state,
+ boolean asc) {
+ sel.orderBy(newSQLBuffer(sel, ctx, state), asc, false, getSelectAs());
+ }
+
+ private SQLBuffer newSQLBuffer(Select sel, ExpContext ctx, ExpState state) {
+ calculateValue(sel, ctx, state, null, null);
+ SQLBuffer buf = new SQLBuffer(ctx.store.getDBDictionary());
+ appendTo(sel, ctx, state, buf, 0);
+ return buf;
+ }
+
+ @Override
+ public Object load(ExpContext ctx, ExpState state, Result res) throws SQLException {
+ return Filters.convert(res.getObject(this, JavaSQLTypes.JDBC_DEFAULT, null), getType());
+ }
+
+ @Override
+ public void calculateValue(Select sel, ExpContext ctx, ExpState state, Val other, ExpState otherState) {
+ ExtractTypecastToNumberExpState etnstate = (ExtractTypecastToNumberExpState) state;
+ _val.calculateValue(sel, ctx, etnstate.valueState, null, null);
+ }
+
+ @Override
+ public int length(Select sel, ExpContext ctx, ExpState state) {
+ return 1;
+ }
+
+ @Override
+ public void appendTo(Select sel, ExpContext ctx, ExpState state, SQLBuffer sql, int index) {
+ DBDictionary dict = ctx.store.getDBDictionary();
+ String func = dict.castFunction;
+
+ int fieldPart = func.indexOf("{0}");
+ int targetPart = func.indexOf("{1}");
+ String part1 = func.substring(0, fieldPart);
+ String part2 = func.substring(fieldPart + 3, targetPart);
+ String part3 = func.substring(targetPart + 3);
+
+ ExtractTypecastToNumberExpState etnstate = (ExtractTypecastToNumberExpState) state;
+ sql.append(part1);
+ _val.appendTo(sel, ctx, etnstate.valueState, sql, 0);
+ sql.append(part2);
+ sql.append(getDbNumberTargetTypeName(dict));
+ sql.append(part3);
+ }
+
+ @Override
+ public void acceptVisit(ExpressionVisitor visitor) {
+ visitor.enter(this);
+ _val.acceptVisit(visitor);
+ visitor.exit(this);
+ }
+
+ @Override
+ public int getId() {
+ return Val.EXTRACTDTF_VAL;
+ }
+
+ private static String sanitize(String type) {
+ final int idx = type.indexOf('{');
+ return idx < 0 ? type : type.substring(0, idx);
+ }
+
+ private String getDbNumberTargetTypeName(DBDictionary dict) {
+ String type;
+ if (getType() == int.class) {
+ type = dict.integerCastTypeName;
+ } else if (getType() == long.class) {
+ type = dict.decimalTypeName;
Review Comment:
**(medium)** Casting to Long uses `dict.decimalTypeName`; on MySQL `CAST(x AS DECIMAL)` defaults to DECIMAL(10,0), so large long values overflow/truncate - why not `bigintTypeName` for the long case? Also `getDbNumberTargetTypeName` sanitizes the `{0}` size suffix while the sibling TypecastAsString.java:152 appends `dict.varcharTypeName` raw - the two siblings should share the same sanitize logic.
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/VersionVal.java:
##########
@@ -0,0 +1,166 @@
+/*
+ * 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.kernel.exps.PCPath.PathExpState;
+import org.apache.openjpa.jdbc.meta.ClassMapping;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.jdbc.sql.SQLBuffer;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.kernel.Filters;
+import org.apache.openjpa.kernel.exps.ExpressionVisitor;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.util.UserException;
+
+/**
+ * Select the version value of an object; typically used in projections.
+ *
+ * @author Abe White
+ * @author Paulo Cristovão Filho
+ */
+class VersionVal
+ extends AbstractVal {
+
+
+ private static final long serialVersionUID = 1L;
+
+ private static final Localizer _loc = Localizer.forPackage(VersionVal.class);
+
+ protected final PCPath _path;
+ private ClassMetaData _meta = null;
+
+ /**
+ * Constructor. Provide the value whose version to extract.
+ */
+ public VersionVal(PCPath path) {
+ _path = path;
+ }
+
+ /**
+ * Return the version column.
+ */
+ public Column[] getColumns(ExpState state) {
+ return _path.getClassMapping(state).getVersionFieldMapping().getColumns();
Review Comment:
**(medium)** `getColumns()` NPEs when the entity has a surrogate version or no version at all (`getVersionFieldMapping()` returns null), so `VERSION(e)` on such an entity dies with NullPointerException instead of a meaningful error - `initialize` should validate this like it validates the class mapping. The error at line 99 also reuses the `bad-getobjectid` message, which is misleading for a VERSION() failure.
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EnumValueHandler.java:
##########
@@ -116,8 +219,26 @@ public Object toDataStoreValue(ValueMapping vm, Object val, JDBCStore store) {
public Object toObjectValue(ValueMapping vm, Object val) {
if (val == null)
return null;
- if (_ordinal)
- return _vals[((Number) val).intValue()];
- return Enum.valueOf(vm.getType(), (String) val);
+ if (_useEnumeratedValue) {
+ initEnumeratedValueField(vm.getType());
+ Enum<?> result = _dbToEnum.get(val);
+ if (result == null && val instanceof Number) {
+ result = _dbToEnum.get(((Number) val).intValue());
+ }
+ if (result == null) {
+ result = _dbToEnum.get(val.toString());
+ }
+ return result;
Review Comment:
**(medium)** When an `@EnumeratedValue` lookup fails for a DB value, `toObjectValue` silently returns null - an unexpected column value becomes a null enum with no diagnostic. Should this throw like `Enum.valueOf` does for the name-based path? Separately, the lazy init at lines 152-168 sets `_enumeratedValueField` before `_dbToEnum`, so a concurrent reader passing the early-return at line 153 can hit a null `_dbToEnum` - worth initializing both before publishing.
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/StoredProcedureQuery.java:
##########
@@ -196,18 +224,25 @@ public ResultObjectProvider executeQuery(StoreQuery q, Object[] params, Range ra
@Override
public Object[] toParameterArray(StoreQuery q, Map<?, ?> userParams) {
- if (userParams == null) return NO_PARAM;
- Object[] array = new Object[userParams.size()];
+ if (userParams == null || userParams.isEmpty()) return NO_PARAM;
+ StoredProcedureQuery storedProcedureQuery = (StoredProcedureQuery) q;
+ Column[] inCols = storedProcedureQuery.getProcedure().getInColumns();
+ Column[] inOutCols = storedProcedureQuery.getProcedure().getInOutColumns();
+ int paramCount = inCols.length + inOutCols.length;
+ if (paramCount == 0) return NO_PARAM;
+ Object[] array = new Object[paramCount];
int i = 0;
- StoredProcedureQuery storedProcedureQuery = StoredProcedureQuery.class.cast(q);
- for (final Column[] columns : asList(
- storedProcedureQuery.getProcedure().getInColumns(),
- storedProcedureQuery.getProcedure().getInOutColumns())) {
+ for (final Column[] columns : asList(inCols, inOutCols)) {
for (Column c : columns) {
- array[i] = userParams.get(c.getIdentifier().getName());
- if (array[i++] == null) {
- userParams.get(c.getIndex());
+ // Try by name first, then by 1-based position (matching user's declaration)
Review Comment:
**(medium)** Using `userParams.get(name) == null` to fall through to positional lookup means an explicitly bound null named parameter is silently replaced by whatever is registered under the position key - `containsKey` should distinguish "bound to null" from "absent". Related: the new `c.getIndex() < params.length` guards at lines 188/195 silently skip binding instead of failing, turning a caller bug into an unbound-parameter SQLException far from the cause.
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java:
##########
@@ -842,6 +1055,13 @@ public void connectedConfiguration(Connection conn) throws SQLException {
if ((maj <= 8 || (maj == 9 && min == 0))) {
searchStringEscape = "\\\\";
}
+
+ // Modern PostgreSQL supports native CHAR storage; only the older
+ // releases required the DBDictionary default (chars stored as
+ // numeric values).
+ if (maj >= 9) {
+ storeCharsAsNumbers = false;
Review Comment:
**(medium)** Flipping `storeCharsAsNumbers` to false for PostgreSQL >= 9 changes the default mapping for existing applications: char fields previously stored in INTEGER columns will now map/validate as CHAR, so schemas created by older OpenJPA versions fail validation or read wrongly after an upgrade. Intended compatibility break? Should be release-noted and overridable.
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java:
##########
@@ -477,7 +823,160 @@ public boolean isLoaded(Object entity, String attribute) {
return (OpenJPAPersistenceUtil.isManagedBy(this, entity) &&
(OpenJPAPersistenceUtil.isLoaded(entity, attribute) == LoadState.LOADED));
}
-
+
+ @Override
+ public <E> boolean isLoaded(E entity, Attribute<? super E, ?> attribute) {
+ return isLoaded(entity, attribute.getName());
+ }
+
+ @Override
+ public SchemaManager getSchemaManager() {
+ if (!this.isOpen()) {
+ throw new IllegalStateException("EntityManagerFactory is closed.");
+ }
+ return new SchemaManagerImpl(_factory);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <R> R callInTransaction(Function<EntityManager, R> work) {
+ EntityManager em = createEntityManager();
+ boolean startedTransaction = false;
+ boolean jtaTransaction = getTransactionType() == PersistenceUnitTransactionType.JTA;
+ Broker broker = em.unwrap(Broker.class);
+ try {
+ if (jtaTransaction) {
+ if (!broker.syncWithManagedTransaction()) {
+ broker.begin();
+ startedTransaction = true;
+ }
+ } else {
+ em.getTransaction().begin();
+ startedTransaction = true;
+ }
+ R result = work.apply(em);
+ if (startedTransaction) {
+ if (jtaTransaction) {
+ broker.commit();
+ } else {
+ em.getTransaction().commit();
+ }
+ }
+ // For unenhanced (runtime-subclassed) entities, the user's function
+ // may return an original POJO that was passed to persist().
+ // Entities loaded via find() on other EMs are subclass instances,
+ // causing getClass() mismatches in equals(). To ensure consistent
+ // class identity, re-find managed entities from the database so that
+ // the returned instance is a subclass (matching what find() returns).
+ if (result != null && em.contains(result)) {
+ try {
+ Object id = getPersistenceUnitUtil().getIdentifier(result);
+ if (id != null) {
+ Class<R> entityClass = (Class<R>) result.getClass();
+ em.clear();
+ R refound = em.find(entityClass, id);
+ if (refound != null) {
+ result = refound;
+ }
+ }
+ } catch (Exception e) {
+ // If re-find fails, return original result
+ }
+ }
+ return result;
+ } catch (Exception ex) {
+ if (jtaTransaction) {
Review Comment:
**(high)** In the JTA path the catch block calls `broker.rollback()` unconditionally, even when `startedTransaction` is false, i.e. when we merely joined an existing managed transaction. The spec says the JTA transaction must be marked for rollback in that case (`setRollbackOnly`), not rolled back out from under its owner. Can this be made symmetric with the commit path, which correctly checks `startedTransaction`?
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java:
##########
@@ -477,7 +823,160 @@ public boolean isLoaded(Object entity, String attribute) {
return (OpenJPAPersistenceUtil.isManagedBy(this, entity) &&
(OpenJPAPersistenceUtil.isLoaded(entity, attribute) == LoadState.LOADED));
}
-
+
+ @Override
+ public <E> boolean isLoaded(E entity, Attribute<? super E, ?> attribute) {
+ return isLoaded(entity, attribute.getName());
+ }
+
+ @Override
+ public SchemaManager getSchemaManager() {
+ if (!this.isOpen()) {
+ throw new IllegalStateException("EntityManagerFactory is closed.");
+ }
+ return new SchemaManagerImpl(_factory);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <R> R callInTransaction(Function<EntityManager, R> work) {
+ EntityManager em = createEntityManager();
+ boolean startedTransaction = false;
+ boolean jtaTransaction = getTransactionType() == PersistenceUnitTransactionType.JTA;
+ Broker broker = em.unwrap(Broker.class);
+ try {
+ if (jtaTransaction) {
+ if (!broker.syncWithManagedTransaction()) {
+ broker.begin();
+ startedTransaction = true;
+ }
+ } else {
+ em.getTransaction().begin();
+ startedTransaction = true;
+ }
+ R result = work.apply(em);
+ if (startedTransaction) {
+ if (jtaTransaction) {
+ broker.commit();
+ } else {
+ em.getTransaction().commit();
+ }
+ }
+ // For unenhanced (runtime-subclassed) entities, the user's function
+ // may return an original POJO that was passed to persist().
+ // Entities loaded via find() on other EMs are subclass instances,
+ // causing getClass() mismatches in equals(). To ensure consistent
+ // class identity, re-find managed entities from the database so that
+ // the returned instance is a subclass (matching what find() returns).
+ if (result != null && em.contains(result)) {
+ try {
+ Object id = getPersistenceUnitUtil().getIdentifier(result);
+ if (id != null) {
+ Class<R> entityClass = (Class<R>) result.getClass();
+ em.clear();
+ R refound = em.find(entityClass, id);
+ if (refound != null) {
+ result = refound;
+ }
+ }
+ } catch (Exception e) {
+ // If re-find fails, return original result
+ }
+ }
+ return result;
+ } catch (Exception ex) {
+ if (jtaTransaction) {
+ broker.rollback();
+ } else {
+ try {
+ em.getTransaction().rollback();
+ } catch (Exception rollbackEx) {
+ // Transaction may already be rolled back
+ }
+ }
+ throw new UserException(ex.getMessage(), ex);
Review Comment:
**(high)** Per the JPA 3.2 javadoc for `callInTransaction`/`runInTransaction`, an exception thrown by the function must be rethrown after rollback, not wrapped. Wrapping everything in `org.apache.openjpa.util.UserException` swallows the caller's original exception type, and UserException is not a `jakarta.persistence.PersistenceException`, so callers cannot catch it portably. Should this simply rethrow RuntimeException as-is?
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AbstractQuery.java:
##########
@@ -309,7 +325,7 @@ public OpenJPAQuery<X> setParameters(Map params) {
@Override
public <T> Parameter<T> getParameter(String name, Class<T> type) {
Parameter<?> param = getParameter(name);
- if (param.getParameterType().isAssignableFrom(type))
+ if (!param.getParameterType().isAssignableFrom(type))
Review Comment:
**(medium)** The assignability check looks inverted: per the javadoc, the parameter's type must be assignable to the requested type, i.e. `type.isAssignableFrom(param.getParameterType())`. As written, `getParameter("x", Object.class)` on an Integer-typed parameter throws although it should succeed. Same at line 347.
##########
openjpa-project/src/doc/manual/openjpa_legal.xml:
##########
@@ -87,19 +87,19 @@ The openjpa-all aggregate JAR includes software developed by the:
<section id="openjpa_legal_copyright_apache">
<title>Apache</title>
<para>
-Copyright (C) 2006,2011 The Apache Software Foundation.
+Copyright (C) 2006,2026 The Apache Software Foundation.
</para>
<para>
Apache, OpenJPA and the Apache feather logo are trademarks of Apache Software Foundation.
</para>
</section>
<section id="openjpa_legal_copyright_sun">
- <title>Sun</title>
+ <title>Eclipse</title>
<para>
OpenJPA includes the persistence and orm schemas from the JPA specifications.
</para>
<para>
-Copyright 2005-2009 Sun Microsystems, Inc. All rights reserved.
+Copyright (c) [2024] Eclipse Foundation AISBL <ulink url="https://jakarta.ee/specifications/persistence/3.2/jakarta-persistence-spec-3.2#eclipse-foundation-specification-license-v1-1">EFSL 1.1</ulink>
Review Comment:
**(medium)** Two nits: the template brackets survived in "Copyright (c) [2024] Eclipse Foundation AISBL", and the next paragraph still says "OpenJPA elects to include this software in this distribution under the CDDL license" while the surrounding text was changed to EFSL 1.1 - should the CDDL sentence be updated for consistency?
##########
openjpa-integration/tck/README.md:
##########
@@ -0,0 +1,130 @@
+# OpenJPA JPA 3.2 TCK Runner
+
+This module runs the Jakarta Persistence 3.2 Technology Compatibility Kit (TCK)
+against OpenJPA using PostgreSQL.
+
+## Prerequisites
+
+- Java 17+
+- Maven 3.x
+- PostgreSQL (via Docker or a standalone instance)
+- `psql` command-line client (for database preparation)
+- `python3`, `curl`, `unzip` (the script checks for all required commands at startup)
+
+## Quick Start
+
+### 1. Start PostgreSQL
+
+From the **project root**:
+
+```bash
+docker compose up -d
Review Comment:
**(high)** The Quick Start says `docker compose up -d` and points at "the docker-compose.yml in the project root", but no compose file is committed - it is even listed in `.gitignore`. The documented defaults (localhost:5433, openjpa/openjpa, openjpa_tck, psql/python3 prerequisites) also do not match `run-tck32.sh` (localhost:5555, tcktest/tcktest/tcktest; the script only checks java/mvn/curl/unzip/grep/sed). Could you either commit the compose file or rewrite the README around the script's `docker:start` flow?
##########
.gitignore:
##########
@@ -11,3 +11,11 @@ nbactions*.xml
.checkstyle
.vscode
+.claude
Review Comment:
**(low)** `.claude`/`CLAUDE.md` are personal tooling files that usually belong in a developer's global gitignore rather than the project one; `tck-dev`/`pgdata`/`docker-compose.yml` look like local dev leftovers too (and ignoring `docker-compose.yml` conflicts with the TCK README referencing it). Can this list be trimmed?
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java:
##########
@@ -2246,4 +2639,215 @@ private QueryMetaData getQueryMetadata(String name) {
}
return meta;
}
+
+ @Override
+ public <T> T find(EntityGraph<T> entityGraph, Object primaryKey, FindOption... options) {
+ throw new UnsupportedOperationException("Not yet implemented (JPA 3.2)");
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getReference(T entity) {
+ assertNotCloseInvoked();
+ if (entity == null) {
+ throw new IllegalArgumentException("entity is null");
+ }
+ // JPA 3.2: getReference(entity) extracts the entity class and PK,
+ // then delegates to getReference(Class, Object) for lazy loading
+ Class<T> entityClass = (Class<T>) entity.getClass();
+ ClassMetaData meta = _broker.getConfiguration()
+ .getMetaDataRepositoryInstance()
+ .getMetaData(entityClass, null, false);
+ if (meta == null) {
+ throw new IllegalArgumentException(
+ _loc.get("not-entity", entityClass).getMessage());
+ }
+ // Extract the primary key value from the entity instance
+ FieldMetaData[] pkFields = meta.getPrimaryKeyFields();
+ Object pk = null;
+ if (pkFields.length == 1) {
+ FieldMetaData pkField = pkFields[0];
+ if (pkField.getBackingMember() instanceof Method) {
+ try {
+ pk = ((Method) pkField.getBackingMember()).invoke(entity);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Cannot extract PK from entity", e);
+ }
+ } else if (pkField.getBackingMember() instanceof Field f) {
+ try {
+ f.setAccessible(true);
+ pk = f.get(entity);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Cannot extract PK from entity", e);
+ }
+ }
+ }
+ return getReference(entityClass, pk);
+ }
+
+ @Override
+ public void lock(Object entity, LockModeType lockMode, LockOption... options) {
+ Map<String, Object> properties = null;
+ if (options != null) {
+ properties = new HashMap<>();
+ for (LockOption option : options) {
+ if (option instanceof Timeout) {
+ properties.put("jakarta.persistence.lock.timeout", ((Timeout) option).milliseconds());
+ } else if (option instanceof PessimisticLockScope) {
+ properties.put("jakarta.persistence.lock.scope", option);
+ }
+ }
+ }
+ lock(entity, lockMode, properties);
+ }
+
+ @Override
+ public void refresh(Object entity, RefreshOption... options) {
+ LockModeType lockMode = null;
+ Map<String, Object> properties = null;
+ if (options != null) {
+ properties = new HashMap<>();
+ for (RefreshOption option : options) {
+ if (option instanceof Timeout) {
+ properties.put("jakarta.persistence.lock.timeout", ((Timeout) option).milliseconds());
+ } else if (option instanceof PessimisticLockScope) {
+ properties.put("jakarta.persistence.lock.scope", option);
+ } else if (option instanceof LockModeType) {
+ lockMode = (LockModeType) option;
+ } else if (option instanceof CacheStoreMode) {
+ properties.put("jakarta.persistence.cache.storeMode", option);
+ }
+ }
+ }
+ refresh(entity, lockMode, properties);
+ }
+
+ @Override
+ public CacheRetrieveMode getCacheRetrieveMode() {
+ return getFetchPlan().getCacheRetrieveMode() == DataCacheRetrieveMode.USE ? CacheRetrieveMode.USE : CacheRetrieveMode.BYPASS;
+ }
+
+ @Override
+ public void setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) {
+ getFetchPlan().setCacheRetrieveMode(cacheRetrieveMode == CacheRetrieveMode.USE
+ ? DataCacheRetrieveMode.USE : DataCacheRetrieveMode.BYPASS);
+ }
+
+ @Override
+ public void setCacheStoreMode(CacheStoreMode cacheStoreMode) {
+ DataCacheStoreMode storeMode = switch (cacheStoreMode) {
+ case USE: yield DataCacheStoreMode.USE;
+ case REFRESH: yield DataCacheStoreMode.REFRESH;
+ default: yield DataCacheStoreMode.BYPASS;
+ };
+ getFetchPlan().setCacheStoreMode(storeMode);
+ }
+
+ @Override
+ public CacheStoreMode getCacheStoreMode() {
+ return switch (getFetchPlan().getCacheStoreMode()) {
+ case USE: yield CacheStoreMode.USE;
+ case REFRESH: yield CacheStoreMode.REFRESH;
+ default: yield CacheStoreMode.BYPASS;
+ };
+ }
+
+ @Override
+ public <T> TypedQuery<T> createQuery(CriteriaSelect<T> selectQuery) {
+ if (selectQuery instanceof CriteriaQuery) {
+ return createQuery((CriteriaQuery<T>) selectQuery);
+ }
+
+ org.apache.openjpa.persistence.criteria.CriteriaSelectImpl<T> setOp =
+ (org.apache.openjpa.persistence.criteria.CriteriaSelectImpl<T>) selectQuery;
+ setOp.compile();
+
+ org.apache.openjpa.kernel.Query kernelQuery =
+ _broker.newQuery(OpenJPACriteriaBuilder.LANG_CRITERIA, setOp);
+
+ QueryImpl<T> facadeQuery = newQueryImpl(kernelQuery, null)
+ .setId(selectQuery.toString());
+ Set<ParameterExpression<?>> params = setOp.getParameters();
+ for (ParameterExpression<?> param : params) {
+ facadeQuery.declareParameter(param, param);
+ }
+ return facadeQuery;
+ }
+
+ @Override
+ public <T> TypedQuery<T> createQuery(TypedQueryReference<T> reference) {
+ throw new UnsupportedOperationException("Not yet implemented (JPA 3.2)");
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <C> void runWithConnection(ConnectionConsumer<C> action) {
+ assertNotCloseInvoked();
+ C connection = (C) getConnection();
+ boolean txActive = _broker.isActive();
+ try {
+ action.accept(connection);
+ } catch (Exception e) {
+ throw PersistenceExceptions.toPersistenceException(e);
+ } finally {
+ // Per JPA 3.2, the connection passed to runWithConnection is on
+ // loan to the user code; its lifecycle is owned by the EM/broker
+ // when a transaction is active. Closing the user-facing wrapper
+ // during an active transaction can cause some JDBC drivers (e.g.
+ // MariaDB Connector/J) to discard pending work on the underlying
+ // connection. Only close when no transaction is active (i.e. a
+ // free-standing connection was borrowed).
+ if (!txActive && connection instanceof AutoCloseable) {
+ try {
+ ((AutoCloseable) connection).close();
+ } catch (Exception e) {
+ // ignore close exceptions
+ }
+ }
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <C, T> T callWithConnection(ConnectionFunction<C, T> function) {
+ assertNotCloseInvoked();
+ C connection = (C) getConnection();
+ boolean txActive = _broker.isActive();
+ try {
+ return function.apply(connection);
+ } catch (Exception e) {
+ throw PersistenceExceptions.toPersistenceException(e);
+ } finally {
+ // Per JPA 3.2, the connection passed to callWithConnection is on
+ // loan to the user code; its lifecycle is owned by the EM/broker
+ // when a transaction is active. Closing the user-facing wrapper
+ // during an active transaction can cause some JDBC drivers (e.g.
+ // MariaDB Connector/J) to discard pending work on the underlying
+ // connection. Only close when no transaction is active (i.e. a
+ // free-standing connection was borrowed).
+ if (!txActive && connection instanceof AutoCloseable) {
+ try {
+ ((AutoCloseable) connection).close();
+ } catch (Exception e2) {
+ // ignore close exceptions
+ }
+ }
+ }
+ }
+
+ @Override
+ public void setTimeout(Integer timeout) {
+ assertNotCloseInvoked();
+ if (timeout != null) {
Review Comment:
**(low)** `setTimeout(null)` is silently ignored, so once a timeout is set it can never be cleared through this API (and `getTimeout()` keeps returning the stale value). Should null reset the fetch plan's query timeout to its default?
##########
openjpa-integration/tck/run-tck32.sh:
##########
@@ -0,0 +1,210 @@
+#!/bin/bash
+#
+# 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.
+#
+
+TCK_VERSION="${TCK_VERSION:-3.2.0}"
+TCK_BASE="${TCK_VERSION:0:3}"
+
+SCRIPT_ROOT=$(cd -- $(dirname "${0}") && pwd)
+PROJECT_ROOT="$(cd "${SCRIPT_ROOT}/../.." && pwd)"
+
+# derby is removed for now
+# mysql 8.0 is broken! db.delimiter='!' breaks connection
+declare -A FULL_DB_LIST=(
+ [mysql]=mysql
+ [postgresql]=postgresql
+ [mssql]=mssqlserver
+ [oracle]=oracle
+)
+
+declare -A VERSIONS=(
+ [mysql]='8.4.8' # 8.4.8 9.4.0
+ [postgresql]='16'
+)
+
+#
+# Script to download, setup and run the JPA 3.2 TCK against OpenJPA
+# using DB selected.
+#
+# Usage:
+# ./run-tck32.sh # Run full TCK against postgres:16
+# DB_VERSION=18 ./run-tck32.sh # Run full TCK against postgres:18
+# DB_TYPE=mysql ./run-tck32.sh # Run full TCK against mysql:8.4.8
+# DB_HOST=myhost:5432 ./run-tck32.sh # Custom DB host
+# OPENJPA_VERSION=4.2.0-SNAPSHOT ./run-tck32.sh # Custom OpenJPA version
+#
+# Prerequisites:
+# - OpenJPA must be built and installed in local Maven repo
+# (run 'mvn install -DskipTests' from the project root)
+# - Java 17+ and Maven 3.x
+#
+
+set -e
+
+# Check required commands
+MISSING=""
+for cmd in java mvn curl unzip grep sed; do
+ if ! command -v "$cmd" &>/dev/null; then
+ MISSING="${MISSING} - ${cmd}\n"
+ fi
+done
+if [[ -n "$MISSING" ]]; then
+ echo "ERROR: The following required commands are not available:"
+ echo -e "$MISSING"
+ echo "Please install them before running this script."
+ exit 1
+fi
+
+stopAll() {
+ for profile in ${!FULL_DB_LIST[@]}; do
+ echo "Stopping dockerized ${profile}"
+ mvn -N -Ptest-${profile}-docker -f ${PROJECT_ROOT} -Ddocker.stopNamePattern=${profile:0:8}* docker:stop -Ddocker.showLogs
+ done
+}
+
+stopAll
+
+TCK_URL="https://download.eclipse.org/jakartaee/persistence/${TCK_BASE}/jakarta-persistence-tck-${TCK_VERSION}.zip"
+TCK_DIR="${SCRIPT_ROOT}/target/tck32"
+TCK_ZIP="${TCK_DIR}/jakarta-persistence-tck-${TCK_VERSION}.zip"
+TCK_HOME="${TCK_DIR}/persistence-tck"
+OPENJPA_VERSION="${OPENJPA_VERSION:-4.2.0-SNAPSHOT}"
+START_DOCKER=
+
+if [[ -z "${DB_HOST}" ]]; then
+ START_DOCKER=1
+fi
+
+DB_TYPE="${DB_TYPE:-postgresql}"
+DB_HOST="${DB_HOST:-localhost:5555}"
+DB_USER="${DB_USER:-tcktest}"
+DB_PASSWORD="${DB_PASSWORD:-tcktest}"
+DB_NAME="${DB_NAME:-tcktest}"
+DB_URL=""
+declare -a JPROPS=()
+
+DB_HOST_ONLY="${DB_HOST%%:*}"
+DB_PORT="${DB_HOST##*:}"
+
+TCK_DB_TYPE="${FULL_DB_LIST[${DB_TYPE}]}"
+
+setProps() {
+ local ver="${VERSIONS[${DB_TYPE}]}"
+ if [[ -n "${DB_VERSION}" ]]; then
+ ver="${DB_VERSION}"
+ fi
+ if [[ -n "${VERSIONS[${DB_TYPE}]}" ]]; then
+ JPROPS+=("-D${DB_TYPE}.server.version=${ver}")
+ fi
+
+ case ${DB_TYPE} in
+ mysql)
+ DB_URL="jdbc:mysql://${DB_HOST}/${DB_NAME}?useSSL=false&allowPublicKeyRetrieval=true&transformedBitIsBoolean=true"
+ ;;
+ postgresql)
+ DB_URL="jdbc:postgresql://${DB_HOST}/${DB_NAME}"
+ ;;
+ mssql)
+ DB_NAME=""
+ DB_URL="jdbc:sqlserver://${DB_HOST};sendTimeAsDatetime=false;trustServerCertificate=true"
+ ;;
+ oracle)
+ JPROPS+=("-Dopenjpa.oracle.SID=${DB_NAME}")
+ DB_NAME="XE"
+ DB_URL="jdbc:oracle:thin:@${DB_HOST}:${DB_NAME}"
+ ;;
+ esac
+ JPROPS+=("-Ddocker.external.${DB_TYPE}.port=${DB_PORT}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.dbname=${DB_NAME}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.username=${DB_USER}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.password=${DB_PASSWORD}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.url=${DB_URL}")
+}
+
+setProps
+
+if [[ -n "${START_DOCKER}" ]]; then
+ echo "Starting dockerized ${DB_TYPE}"
+ mvn -N -f ${PROJECT_ROOT} -Ptest-${DB_TYPE}-docker "${JPROPS[@]}" docker:start -Ddocker.showLogs
+fi
+
+GF_VERSION="${GF_VERSION:-8.0.0}"
+
+echo "=== JPA ${TCK_BASE} TCK Runner for OpenJPA ==="
+echo "OpenJPA version: ${OPENJPA_VERSION}"
+echo "TCK version: ${TCK_VERSION}"
+echo "GlassFish: ${GF_VERSION}"
+echo "Database: ${DB_TYPE} (${DB_HOST}/${DB_NAME})"
+echo ""
+
+# Step 1: Download TCK if not present
+mkdir -p "${TCK_DIR}"
+if [[ ! -f "${TCK_ZIP}" ]]; then
+ echo "Downloading JPA ${TCK_BASE} TCK..."
+ curl -sL -o "${TCK_ZIP}" "${TCK_URL}"
+ echo "Downloaded."
+else
+ echo "TCK zip already present, skipping download."
+fi
+
+# Step 2: Extract TCK
+if [[ ! -d "${TCK_HOME}" ]]; then
+ echo "Extracting TCK..."
+ cd "${TCK_DIR}" && unzip -q "${TCK_ZIP}"
+ echo "Extracted."
+else
+ echo "TCK already extracted, skipping."
+fi
+
+# Step 3: Install TCK artifacts into local Maven repo
+echo "Installing TCK artifacts..."
+cd "${TCK_HOME}/artifacts" && bash artifact-install.sh "${TCK_VERSION}"
+echo "TCK artifacts installed."
+
+# Step 4: Patch TCK pom.xml to add OpenJPA profile (if not already patched)
+TCK_POM="${TCK_HOME}/bin/pom.xml"
+if [[ -z "$(grep '<id>openjpa</id>' "${TCK_POM}")" ]]; then
+ echo "Adding OpenJPA profile to TCK pom.xml..."
+
+ sed '/<\/profiles>/,$d' "${TCK_POM}" > temp
+ cat "${SCRIPT_ROOT}/tck32-openjpa-profile.xml" >> temp
+ sed '/<\/profiles>/,$!d' "${TCK_POM}" >> temp
+ mv temp "${TCK_POM}"
+
+ echo "OpenJPA profile added."
+else
+ echo "OpenJPA profile already present in TCK pom.xml."
+fi
+
+echo ""
+echo "=== Preparing ${DB_TYPE} database ==="
Review Comment:
**(low)** "=== Preparing ${DB_TYPE} database ===" is an empty leftover (Step 5 is missing between Step 4 and Step 6), yet the README claims this step drops stale tables and creates stored procedures. Either implement it or drop the heading and fix the README.
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/compat/TestSpecCompatibilityOptions.java:
##########
@@ -411,11 +411,10 @@ public void testOneToManyMapRelation() {
em.getTransaction().begin();
em.getTransaction().commit();
- // on some databases KEY is a forbidden name for columns.
- String keyColumn = getDbDictionary(emf).getInvalidColumnWordSet().contains("KEY")
- ? "KEY0"
- : "KEY";
- assertSQLFragnments(sql, "CREATE TABLE C_U1M_Map_FK", "Uni1MFK_ID", keyColumn);
+ // JPA 3.2 spec 11.1.35: default map key column name is the
+ // concatenation of the field name + "_KEY" (was "KEY"/"KEY0" before).
+ // Field Uni_1ToM_Map_FK.entityCs -> column "entityCs_KEY"
+ assertSQLFragnments(sql, "CREATE TABLE C_U1M_Map_FK", "Uni1MFK_ID", "entityCs_KEY");
Review Comment:
**(medium)** Changing the expected default map-key column from KEY/KEY0 to entityCs_KEY (also TestContainerSpecCompatibilityOptions.java:426 and the KEY0 -> photos_KEY expected SQL in TestTypesafeCriteria) is spec-correct, but silently changes DDL/SQL against existing schemas created by older OpenJPA versions - upgrades will not find the KEY0 column. Should this be gated behind a compatibility option (this test class exists exactly for that) and called out in migration notes?
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java:
##########
@@ -413,6 +526,42 @@ private int determineImplicitAccessType(Class<?> cls, OpenJPAConfiguration
return AccessCode.UNKNOWN;
}
+ /**
+ * Checks whether the given class has JPA annotations on both fields AND
+ * getters, indicating mixed annotation placement.
+ */
+ private boolean hasMixedAnnotations(Class<?> cls, OpenJPAConfiguration conf) {
Review Comment:
**(medium)** `hasMixedAnnotations`, `hasFieldStrategyAnnotations` (547) and `hasGetterStrategyAnnotations` (556) are never called from anywhere - dead code from an earlier iteration of the access-type rework; suggest removing.
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java:
##########
@@ -2246,4 +2639,215 @@ private QueryMetaData getQueryMetadata(String name) {
}
return meta;
}
+
+ @Override
+ public <T> T find(EntityGraph<T> entityGraph, Object primaryKey, FindOption... options) {
+ throw new UnsupportedOperationException("Not yet implemented (JPA 3.2)");
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getReference(T entity) {
+ assertNotCloseInvoked();
+ if (entity == null) {
+ throw new IllegalArgumentException("entity is null");
+ }
+ // JPA 3.2: getReference(entity) extracts the entity class and PK,
+ // then delegates to getReference(Class, Object) for lazy loading
+ Class<T> entityClass = (Class<T>) entity.getClass();
+ ClassMetaData meta = _broker.getConfiguration()
+ .getMetaDataRepositoryInstance()
+ .getMetaData(entityClass, null, false);
+ if (meta == null) {
+ throw new IllegalArgumentException(
+ _loc.get("not-entity", entityClass).getMessage());
+ }
+ // Extract the primary key value from the entity instance
+ FieldMetaData[] pkFields = meta.getPrimaryKeyFields();
Review Comment:
**(medium)** `getReference(T entity)` only extracts the PK when `pkFields.length == 1`; for composite/IdClass/EmbeddedId entities `pk` stays null and the call fails downstream with a misleading "null pk" IllegalArgumentException. Also `entity.getClass()` (line 2657) may be a runtime subclass without direct metadata. Could composite ids be supported via `broker.getObjectId`, or at least fail with an explicit "composite id not supported" message?
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypecastAsCriteria.java:
##########
@@ -0,0 +1,122 @@
+/*
+ * 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.persistence.criteria;
+
+import java.time.LocalDateTime;
+
+import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.Root;
+import jakarta.persistence.criteria.SetJoin;
+
+import org.apache.openjpa.jdbc.sql.DerbyDictionary;
+
+public class TestTypecastAsCriteria extends CriteriaTest {
+
+ public void testTypecastAsString() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // Derby does not support these CASTs
Review Comment:
**(low)** All tests in this new class (and the new testLeft/testRight in TestEJBQLFunction.java:343) silently return on DerbyDictionary, the default database of the CI build - so the new CAST/LEFT/RIGHT coverage never runs in CI. Consider logging the skip and ensuring at least one CI profile exercises them, or implementing the functions with Derby-compatible SQL.
##########
openjpa-integration/tck/run-tck32.sh:
##########
@@ -0,0 +1,210 @@
+#!/bin/bash
+#
+# 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.
+#
+
+TCK_VERSION="${TCK_VERSION:-3.2.0}"
+TCK_BASE="${TCK_VERSION:0:3}"
+
+SCRIPT_ROOT=$(cd -- $(dirname "${0}") && pwd)
+PROJECT_ROOT="$(cd "${SCRIPT_ROOT}/../.." && pwd)"
+
+# derby is removed for now
+# mysql 8.0 is broken! db.delimiter='!' breaks connection
+declare -A FULL_DB_LIST=(
+ [mysql]=mysql
+ [postgresql]=postgresql
+ [mssql]=mssqlserver
+ [oracle]=oracle
+)
+
+declare -A VERSIONS=(
+ [mysql]='8.4.8' # 8.4.8 9.4.0
+ [postgresql]='16'
+)
+
+#
+# Script to download, setup and run the JPA 3.2 TCK against OpenJPA
+# using DB selected.
+#
+# Usage:
+# ./run-tck32.sh # Run full TCK against postgres:16
+# DB_VERSION=18 ./run-tck32.sh # Run full TCK against postgres:18
+# DB_TYPE=mysql ./run-tck32.sh # Run full TCK against mysql:8.4.8
+# DB_HOST=myhost:5432 ./run-tck32.sh # Custom DB host
+# OPENJPA_VERSION=4.2.0-SNAPSHOT ./run-tck32.sh # Custom OpenJPA version
+#
+# Prerequisites:
+# - OpenJPA must be built and installed in local Maven repo
+# (run 'mvn install -DskipTests' from the project root)
+# - Java 17+ and Maven 3.x
+#
+
+set -e
+
+# Check required commands
+MISSING=""
+for cmd in java mvn curl unzip grep sed; do
+ if ! command -v "$cmd" &>/dev/null; then
+ MISSING="${MISSING} - ${cmd}\n"
+ fi
+done
+if [[ -n "$MISSING" ]]; then
+ echo "ERROR: The following required commands are not available:"
+ echo -e "$MISSING"
+ echo "Please install them before running this script."
+ exit 1
+fi
+
+stopAll() {
+ for profile in ${!FULL_DB_LIST[@]}; do
+ echo "Stopping dockerized ${profile}"
+ mvn -N -Ptest-${profile}-docker -f ${PROJECT_ROOT} -Ddocker.stopNamePattern=${profile:0:8}* docker:stop -Ddocker.showLogs
+ done
+}
+
+stopAll
+
+TCK_URL="https://download.eclipse.org/jakartaee/persistence/${TCK_BASE}/jakarta-persistence-tck-${TCK_VERSION}.zip"
+TCK_DIR="${SCRIPT_ROOT}/target/tck32"
+TCK_ZIP="${TCK_DIR}/jakarta-persistence-tck-${TCK_VERSION}.zip"
+TCK_HOME="${TCK_DIR}/persistence-tck"
+OPENJPA_VERSION="${OPENJPA_VERSION:-4.2.0-SNAPSHOT}"
+START_DOCKER=
+
+if [[ -z "${DB_HOST}" ]]; then
+ START_DOCKER=1
+fi
+
+DB_TYPE="${DB_TYPE:-postgresql}"
+DB_HOST="${DB_HOST:-localhost:5555}"
+DB_USER="${DB_USER:-tcktest}"
+DB_PASSWORD="${DB_PASSWORD:-tcktest}"
+DB_NAME="${DB_NAME:-tcktest}"
+DB_URL=""
+declare -a JPROPS=()
+
+DB_HOST_ONLY="${DB_HOST%%:*}"
+DB_PORT="${DB_HOST##*:}"
+
+TCK_DB_TYPE="${FULL_DB_LIST[${DB_TYPE}]}"
+
+setProps() {
+ local ver="${VERSIONS[${DB_TYPE}]}"
+ if [[ -n "${DB_VERSION}" ]]; then
+ ver="${DB_VERSION}"
+ fi
+ if [[ -n "${VERSIONS[${DB_TYPE}]}" ]]; then
+ JPROPS+=("-D${DB_TYPE}.server.version=${ver}")
+ fi
+
+ case ${DB_TYPE} in
+ mysql)
+ DB_URL="jdbc:mysql://${DB_HOST}/${DB_NAME}?useSSL=false&allowPublicKeyRetrieval=true&transformedBitIsBoolean=true"
+ ;;
+ postgresql)
+ DB_URL="jdbc:postgresql://${DB_HOST}/${DB_NAME}"
+ ;;
+ mssql)
+ DB_NAME=""
+ DB_URL="jdbc:sqlserver://${DB_HOST};sendTimeAsDatetime=false;trustServerCertificate=true"
+ ;;
+ oracle)
+ JPROPS+=("-Dopenjpa.oracle.SID=${DB_NAME}")
+ DB_NAME="XE"
+ DB_URL="jdbc:oracle:thin:@${DB_HOST}:${DB_NAME}"
+ ;;
+ esac
+ JPROPS+=("-Ddocker.external.${DB_TYPE}.port=${DB_PORT}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.dbname=${DB_NAME}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.username=${DB_USER}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.password=${DB_PASSWORD}")
+ JPROPS+=("-Dopenjpa.${DB_TYPE}.url=${DB_URL}")
+}
+
+setProps
+
+if [[ -n "${START_DOCKER}" ]]; then
+ echo "Starting dockerized ${DB_TYPE}"
+ mvn -N -f ${PROJECT_ROOT} -Ptest-${DB_TYPE}-docker "${JPROPS[@]}" docker:start -Ddocker.showLogs
+fi
+
+GF_VERSION="${GF_VERSION:-8.0.0}"
+
+echo "=== JPA ${TCK_BASE} TCK Runner for OpenJPA ==="
+echo "OpenJPA version: ${OPENJPA_VERSION}"
+echo "TCK version: ${TCK_VERSION}"
+echo "GlassFish: ${GF_VERSION}"
+echo "Database: ${DB_TYPE} (${DB_HOST}/${DB_NAME})"
+echo ""
+
+# Step 1: Download TCK if not present
+mkdir -p "${TCK_DIR}"
+if [[ ! -f "${TCK_ZIP}" ]]; then
+ echo "Downloading JPA ${TCK_BASE} TCK..."
+ curl -sL -o "${TCK_ZIP}" "${TCK_URL}"
Review Comment:
**(high)** `curl -sL` without `-f` will happily save a 404/error page as the TCK zip and then cache it forever (the `if [[ ! -f ... ]]` guard never re-downloads). Suggest `curl -fSL` plus verifying the published SHA-256 of the TCK zip before use - integrity matters since these runs may back compatibility claims.
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestJava8TimeTypes.java:
##########
@@ -255,12 +265,70 @@ public void testGetCurrentLocalDateTime() {
}
public void testGetCurrentLocalTime() {
+ DBDictionary dict = getDbDictionary(emf);
+ if (dict instanceof OracleDictionary) {
+ // Oracle has no TIME data type
+ return;
+ }
+
EntityManager em = emf.createEntityManager();
- final TypedQuery<Java8TimeTypes> qry
- = em.createQuery("select j from Java8TimeTypes AS j where j.localTimeField < LOCAL TIME", Java8TimeTypes.class);
+ final TypedQuery<Java8TimeTypes> qry = em.createQuery(
+ "select j from Java8TimeTypes AS j where j.localTimeField < LOCAL TIME OR j.localTimeField >= LOCAL TIME", Java8TimeTypes.class);
Review Comment:
**(high)** The query in testGetCurrentLocalTime was changed to `localTimeField < LOCAL TIME OR localTimeField >= LOCAL TIME`, a tautology matching every row no matter what LOCAL TIME evaluates to. The test now only verifies the query parses. Could we keep an assertion that actually constrains the result (e.g. compare against a value persisted just before)?
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java:
##########
@@ -477,7 +823,160 @@ public boolean isLoaded(Object entity, String attribute) {
return (OpenJPAPersistenceUtil.isManagedBy(this, entity) &&
(OpenJPAPersistenceUtil.isLoaded(entity, attribute) == LoadState.LOADED));
}
-
+
+ @Override
+ public <E> boolean isLoaded(E entity, Attribute<? super E, ?> attribute) {
+ return isLoaded(entity, attribute.getName());
+ }
+
+ @Override
+ public SchemaManager getSchemaManager() {
+ if (!this.isOpen()) {
+ throw new IllegalStateException("EntityManagerFactory is closed.");
+ }
+ return new SchemaManagerImpl(_factory);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <R> R callInTransaction(Function<EntityManager, R> work) {
+ EntityManager em = createEntityManager();
+ boolean startedTransaction = false;
+ boolean jtaTransaction = getTransactionType() == PersistenceUnitTransactionType.JTA;
+ Broker broker = em.unwrap(Broker.class);
+ try {
+ if (jtaTransaction) {
+ if (!broker.syncWithManagedTransaction()) {
+ broker.begin();
+ startedTransaction = true;
+ }
+ } else {
+ em.getTransaction().begin();
+ startedTransaction = true;
+ }
+ R result = work.apply(em);
+ if (startedTransaction) {
+ if (jtaTransaction) {
+ broker.commit();
+ } else {
+ em.getTransaction().commit();
+ }
+ }
+ // For unenhanced (runtime-subclassed) entities, the user's function
+ // may return an original POJO that was passed to persist().
+ // Entities loaded via find() on other EMs are subclass instances,
+ // causing getClass() mismatches in equals(). To ensure consistent
+ // class identity, re-find managed entities from the database so that
+ // the returned instance is a subclass (matching what find() returns).
+ if (result != null && em.contains(result)) {
+ try {
+ Object id = getPersistenceUnitUtil().getIdentifier(result);
+ if (id != null) {
+ Class<R> entityClass = (Class<R>) result.getClass();
+ em.clear();
+ R refound = em.find(entityClass, id);
+ if (refound != null) {
+ result = refound;
+ }
+ }
+ } catch (Exception e) {
+ // If re-find fails, return original result
+ }
+ }
+ return result;
+ } catch (Exception ex) {
+ if (jtaTransaction) {
+ broker.rollback();
+ } else {
+ try {
+ em.getTransaction().rollback();
+ } catch (Exception rollbackEx) {
+ // Transaction may already be rolled back
+ }
+ }
+ throw new UserException(ex.getMessage(), ex);
+ } finally {
+ em.close();
+ }
+ }
+
+ @Override
+ public void runInTransaction(Consumer<EntityManager> work) {
+ callInTransaction(em -> {
+ work.accept(em);
+ return null;
+ });
+ }
+
+ @Override
+ public <T> Class<? extends T> getClass(T entity) {
+ if (!OpenJPAPersistenceUtil.isManagedBy(this, entity)) {
+ throw new jakarta.persistence.PersistenceException(_loc.get("invalid_entity_argument",
+ "getClass", entity == null ? "null" : Exceptions.toString(entity)).getMessage());
+ }
+ return OpenJPAPersistenceUtil.getClass(this, entity);
+ }
+
+ @Override
+ public <R> Map<String, TypedQueryReference<R>> getNamedQueries(Class<R> resultType) {
Review Comment:
**(low)** `getNamedQueries(Class)` still throws UnsupportedOperationException, as do `EntityManagerImpl.createQuery(TypedQueryReference)` (EntityManagerImpl.java:2779) and `find(EntityGraph, Object, FindOption...)` (EntityManagerImpl.java:2645). These are mandatory JPA 3.2 API - planned before merge, or tracked in a follow-up JIRA? Worth referencing the issue in the exception message.
##########
openjpa-integration/tck/run-tck32.sh:
##########
@@ -0,0 +1,210 @@
+#!/bin/bash
+#
+# 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.
+#
+
+TCK_VERSION="${TCK_VERSION:-3.2.0}"
+TCK_BASE="${TCK_VERSION:0:3}"
+
+SCRIPT_ROOT=$(cd -- $(dirname "${0}") && pwd)
+PROJECT_ROOT="$(cd "${SCRIPT_ROOT}/../.." && pwd)"
+
+# derby is removed for now
+# mysql 8.0 is broken! db.delimiter='!' breaks connection
+declare -A FULL_DB_LIST=(
+ [mysql]=mysql
+ [postgresql]=postgresql
+ [mssql]=mssqlserver
+ [oracle]=oracle
+)
+
+declare -A VERSIONS=(
+ [mysql]='8.4.8' # 8.4.8 9.4.0
+ [postgresql]='16'
+)
+
+#
+# Script to download, setup and run the JPA 3.2 TCK against OpenJPA
+# using DB selected.
+#
+# Usage:
+# ./run-tck32.sh # Run full TCK against postgres:16
+# DB_VERSION=18 ./run-tck32.sh # Run full TCK against postgres:18
+# DB_TYPE=mysql ./run-tck32.sh # Run full TCK against mysql:8.4.8
+# DB_HOST=myhost:5432 ./run-tck32.sh # Custom DB host
+# OPENJPA_VERSION=4.2.0-SNAPSHOT ./run-tck32.sh # Custom OpenJPA version
+#
+# Prerequisites:
+# - OpenJPA must be built and installed in local Maven repo
+# (run 'mvn install -DskipTests' from the project root)
+# - Java 17+ and Maven 3.x
+#
+
+set -e
+
+# Check required commands
+MISSING=""
+for cmd in java mvn curl unzip grep sed; do
+ if ! command -v "$cmd" &>/dev/null; then
+ MISSING="${MISSING} - ${cmd}\n"
+ fi
+done
+if [[ -n "$MISSING" ]]; then
+ echo "ERROR: The following required commands are not available:"
+ echo -e "$MISSING"
+ echo "Please install them before running this script."
+ exit 1
+fi
+
+stopAll() {
Review Comment:
**(medium)** `stopAll` runs unconditionally at startup and issues `docker:stop` with name patterns like `postgres*`/`mysql*` for all four DB profiles, even when `DB_HOST` points at an external database - that can kill unrelated containers on a developer machine and adds four mvn invocations per run. Suggest guarding with `START_DOCKER` and limiting to the selected `DB_TYPE`.
##########
scripts/run-build-matrix.sh:
##########
@@ -0,0 +1,222 @@
+#!/bin/bash
+
+SCRIPT_ROOT=$(cd -- $(dirname "${0}") && pwd)
+PROJECT_ROOT="$(cd "${SCRIPT_ROOT}/.." && pwd)"
+declare -A FULL_DB_LIST=(
+ [h2]=embedded
+ [derby]=embedded
+ [hsqldb]=embedded
+ [mysql]=docker
+ [mariadb]=docker
+ [postgresql]=docker
+ [mssql]=docker
+ [herddb]=docker
+ [oracle]=docker
+)
+declare -A VERSIONS=(
+ [mysql]='8.0 8.4.8 9.4.0'
+ [postgresql]='11 16 18'
+)
+COLOR_RED="\033[1;31m"
+COLOR_GREEN="\033[1;32m"
+COLOR_RESET="\033[0m"
+MATRIX=${!FULL_DB_LIST[@]}
+EXCLUDE=''
+REPORT_DIR=.report
+START_WITH=''
+declare -a JPROPS=()
+OFFLINE=
+
+usage() {
+ echo "usage ${0} [-s|--start-with DB_ALIAS] [-r|--report-dir DIR] [-m|--matrix user_matrix] [-e|--exclude exclude_list] [-o|--offline] [-h|--help]"
+ echo -e "\t-s|--start-with DB_ALIAS -- option to skip some databases in the begininning (continue from) [def: '${START_WITH}']"
+ echo -e "\t-r|--report-dir DIR -- the folder with report and logs (will be autocreated) [def: '${REPORT_DIR}']"
+ echo -e "\t-m|--matrix user_matrix -- test matrix in the format 'db1:ver1,ver2;db2;db3:ver3;...' [def db list: ${MATRIX[@]}]"
+ echo -e "\ti.e DB delimiter is ';', in case version(s) should be specified it MUST follow after ':' and have ',' as delimiter"
+ echo -e "\texample: \"-m=oracle\" or \"--matrix='oracle;mysql:8.0'\" or \"--matrix 'postgresql:16,18;mysql:9.4.0'\""
+ echo -e "\t-e|--exclude exclude_list -- exclude DBs from run 'db1;db2;db3;...' [def exclude list: ${EXCLUDE}]"
+ echo -e "\t-o|--offline -- will run tests in offline mode"
+ echo -e "\t-h|--help -- this help message"
+ echo
+ echo -e "\tPlease NOTE: lists for [-m|--matrix user_matrix] [-e|--exclude exclude_list] params should be 'singel_quoted'"
+ echo -e "\tPlease NOTE: additional build parameters can be passed via '-D*' for ex. '-Ddocker.cpus=4' ..."
+}
+
+user_matrix=''
+
+while [[ $# -gt 0 ]]; do
+ case ${1} in
+ -s=*|--start-with=*)
+ START_WITH="${1#*=}"
+ shift
+ ;;
+ -s|--start-with)
+ START_WITH="${2}"
+ shift 2
+ ;;
+ -r=*|--report-dir=*)
+ REPORT_DIR="${1#*=}"
+ shift
+ ;;
+ -r|--report-dir)
+ REPORT_DIR="${2}"
+ shift 2
+ ;;
+ -m=*|--matrix=*)
+ user_matrix="${1#*=}"
+ shift
+ ;;
+ -m|--matrix)
+ user_matrix="${2}"
+ shift 2
+ ;;
+ -e=*|--exclude=*)
+ EXCLUDE="${1#*=}"
+ shift
+ ;;
+ -e|--exclude)
+ EXCLUDE="${2}"
+ shift 2
+ ;;
+ -o|--offline)
+ OFFLINE=-o
+ shift
+ ;;
+ -h|--help)
+ usage
+ exit 0
+ shift
+ ;;
+ -D*)
+ JPROPS+=("${1}")
+ shift
+ ;;
+ *)
+ echo "Unknown option ${1}"
+ usage
+ exit 1
+ ;;
+ esac
+done
+
+stopAll() {
+ for profile in ${MATRIX[@]}; do
+ if [[ "${FULL_DB_LIST[${profile}]}" == "docker" ]]; then
+ mvn -N -Ptest-${profile}-docker -Ddocker.stopNamePattern=${profile:0:8}* docker:stop -Ddocker.showLogs
+ fi
+ done
+}
+
+cd "${PROJECT_ROOT}"
+
+stopAll
+
+if [[ -n "${user_matrix}" ]]; then
+ MATRIX=()
+ IFS=';' read -r -a dbvers <<< "${user_matrix}"
+ for dbver in ${dbvers[@]}; do
+ if [[ -z "${dbver}" ]]; then
+ continue
+ fi
+ IFS=':' read -r -a db_vers <<< "${dbver}"
+ if [[ ${#db_vers[@]} == 1 ]]; then
+ db=${db_vers[0]}
+ vers=''
+ else
+ db=${db_vers[0]}
+ vers=${db_vers[1]}
+ fi
+ MATRIX+=(${db})
+ if [[ -n "${vers}" ]]; then
+ VERSIONS+=([${db}]=$(echo -n "${vers}" | sed -r 's/[,]/ /g'))
+ fi
+ done
+fi
+
+stopAll
+
+REPORT_DIR="${SCRIPT_ROOT}/${REPORT_DIR}"
+REPORT_FILE="${REPORT_DIR}/report.txt"
+if [[ -d "${REPORT_DIR}" ]]; then
+ rm -rf "${REPORT_DIR}"/*
+else
+ mkdir -p "${REPORT_DIR}"
+fi
+echo "" > "${REPORT_FILE}"
+
+do_test() {
+ local profile=${1}
+ local log=${2}
+ local -n params=${3}
+ local status="${COLOR_RED}Failed${COLOR_RESET}"
+ rm -rf openjpa-xmlstore/jdbc:*
+
+ if [[ "${profile}" == *docker ]]; then
+ set -x
+ mvn -N -P${profile} "${params[@]}" docker:start -Ddocker.showLogs
+ local retCode=$?
+ set +x
+ if [[ ${retCode} != 0 ]]; then
+ echo "Failed -- ${log} (can't start docker)" |tee -a ${REPORT_FILE}
+ return 1
+ fi
+ fi
+ set -x
+ mvn clean install -P${profile} "${params[@]}" "${JPROPS[@]}" -Drat.skip ${OFFLINE} &> ${REPORT_DIR}/build_${log}.log
+ local retCode=$?
+ set +x
+ if [[ ${retCode} == 0 ]]; then
+ status="${COLOR_GREEN}Passed${COLOR_RESET}"
+ fi
+ if [[ "${profile}" == *docker ]]; then
+ set -x
+ mvn -N -P${profile} "${params[@]}" docker:stop -Ddocker.showLogs
+ set +x
+ fi
+ echo -e "${status} -- ${log}"
+ echo -e "${status} -- ${log}" >> ${REPORT_FILE}
+ echo " ----------------- "
+}
+
+test_profile() {
+ local mode=${1}
+ local profile=${2}
+ if [[ -n "${START_WITH}" ]]; then
+ if [[ "${profile}" == "${START_WITH}" ]]; then
+ START_WITH=""
+ else
+ echo "Skipping ${profile} ..."
+ continue
Review Comment:
**(high)** `continue` at function top level does not reach the caller's loop in bash >= 4.4 - it prints "continue: only meaningful in a for/while/until loop" and execution just falls through, so `--start-with` prints "Skipping X" and then runs the profile anyway. Should be `return 0`.
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilderImpl.java:
##########
@@ -364,38 +425,50 @@ public <T> Expression<T> function(String name, Class<T> type,
}
@Override
+ @SuppressWarnings("unchecked")
public <X, T, V extends T> Join<X, V> treat(Join<X, T> join, Class<V> type) {
Review Comment:
**(medium)** Only `treat(Root)` gets a real implementation (`RootImpl.TreatedRoot`); all the join overloads (lines 429-450) and `treat(Path)` (line 458) just cast and return the same object. That is a silent no-op: no type narrowing is applied, but instead of the previous explicit UnsupportedOperationException users now get wrong behavior with no diagnostic. Could the unsupported overloads keep throwing (or get a TreatedJoin analogous to TreatedRoot)?
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/batch/exception/TestBatchLimitException.java:
##########
@@ -353,13 +363,14 @@ public void verifyFailedObject(Throwable excp) throws Throwable {
Ent1 failedObject = (Ent1) e.getFailedObject();
assertNotNull("Failed object was null.", failedObject);
- if (!isOracle && !isPostgres) {
+ if (!isOracle && !isPostgres && !isMariaDB) {
Review Comment:
**(low)** The MariaDB branch now accepts either the per-row or first-row failed object/message "across versions", weakening the exact-match check still applied to other DBs. If specific MariaDB versions differ, could the comment name the versions observed so this does not quietly absorb future regressions?
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceUnitInfoImpl.java:
##########
@@ -614,4 +615,52 @@ public SharedCacheMode getSharedCacheMode() {
public void setSharedCacheMode(SharedCacheMode mode) {
_sharedCacheMode = mode;
}
+
+ public void setScopeAnnotationName(String scopeAnnotationName) {
+ _scopeAnnotationName = scopeAnnotationName;
+ }
+
+ @Override
+ public String getScopeAnnotationName() {
+ return _scopeAnnotationName;
+ }
+
+ public void addQualifierAnnotationNames(String qualifierAnnotationName) {
+ if (_qualifierAnnotationNames == null) {
+ _qualifierAnnotationNames = new ArrayList<String>();
+ }
+ _qualifierAnnotationNames.add(qualifierAnnotationName);
+ }
+
+ @Override
+ public List<String> getQualifierAnnotationNames() {
+ if (_qualifierAnnotationNames == null) {
+ return List.of();
+ }
+ return _qualifierAnnotationNames;
+ }
+
+ public static PersistenceUnitInfoImpl convert(PersistenceConfiguration config) {
Review Comment:
**(medium)** `convert(PersistenceConfiguration)` mutates the caller's configuration object (`config.property(...)` for MetaDataFactory and noPersistenceXMLResource) - a surprising side effect for a converter, and repeated `createEntityManagerFactory(config)` calls keep appending. It also ignores `config.mappingFiles()` and `config.qualifiers()` entirely, and `setPersistenceUnitName(config.name())` is called twice (lines 648 and 662). Could the OpenJPA-specific properties go into the returned map instead, and mapping files be wired through?
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/JPAProperties.java:
##########
@@ -130,9 +130,9 @@ public static <T> T convertToKernelValue(Class<T> resultType, String key, Objec
if (JPAProperties.isValidKey(key)) {
// works because enum values are identical String
if (value instanceof CacheRetrieveMode || (value instanceof String && CACHE_RETRIEVE_MODE.equals(key))) {
Review Comment:
**(medium)** The early `return (T) value;` now also fires for String values of `cache.retrieveMode`/`cache.storeMode`, skipping the enum conversion below. Since EntityManagerImpl now exposes `setCacheRetrieveMode(CacheRetrieveMode)`, `em.setProperty("jakarta.persistence.cache.retrieveMode", "USE")` will try to inject a raw String into the enum setter and fail, whereas the old code converted it. Should Strings still be converted to the target enum here?
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/TestBiDirectionalJoinTable.java:
##########
@@ -111,8 +113,8 @@ public void testSingleDelete() {
em.getTransaction().commit();
assertEquals(0, count(Person.class));
- assertEquals(0, count(Address.class));
- assertSQL("DELETE FROM .*J_PERSON_ADDRESSES .*");
+ // JPA 3.2 spec section 4.10: bulk DELETE does not cascade
Review Comment:
**(high)** testSingleDelete/testBulkDelete were inverted from "addresses deleted" to "addresses remain" citing spec 4.10 - but that clause has said bulk delete does not cascade since JPA 1.0, so this is a deliberate break with long-standing OpenJPA behavior rather than something new in 3.2. Also the `assertSQL("DELETE FROM .*J_PERSON_ADDRESSES .*")` assertions were dropped entirely: are the join-table rows still cleaned up, or do we now leave dangling rows pointing at deleted pks (FK violation on constrained schemas)? Please keep an assertion on the join-table state and consider a compatibility option plus release note. Same change in TestBulkJPQLAndDataCache.java:122.
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/kernel/TestSecurityContext.java:
##########
@@ -1,250 +0,0 @@
-/*
Review Comment:
**(low)** This is the only deleted test file; deletion looks justified (SecurityManager removal on modern JDKs), but please state the rationale in the PR description so the removal is clearly intentional.
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
Review Comment:
**(medium)** The oracle profile bind-mounts `${project.basedir}/../jdbc_oradata`, which for the root pom resolves outside the checkout (and to a different path per module since profiles are inherited); run-build-matrix.sh then pre-creates it with `chmod a+rwx` and warns that cleanup needs sudo. Would a named docker volume (or a path under `target/`) be cleaner so nothing leaks outside the repo?
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java:
##########
@@ -1341,6 +1376,90 @@ private void parseMemberAnnotations(FieldMetaData fmd) {
}
}
+ /**
Review Comment:
**(low)** The javadoc for `applyFieldConvert` is duplicated verbatim (two identical blocks back to back at 1379-1383 and 1384-1388); one should go.
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/sqlcache/TestExternalizedParameter.java:
##########
@@ -56,48 +56,44 @@ public void setUp() throws Exception {
}
}
+ /**
+ * Verifies that a query with a non-externalized parameter executes
+ * correctly.
+ */
public void testNoFalseAlarmOnExternalizedParameterDetection() {
String jpql = "select b from Book b where b.title=:title";
EntityManager em = emf.createEntityManager();
- QueryExpressions[] exps = getExpressions(em.createQuery(jpql)
+ List<?> result = em.createQuery(jpql)
.setParameter("title","XYZ")
- .getResultList());
- assertNotNull(exps);
-
- assertFalse(isUsingExternalizedParameter(exps[0]));
+ .getResultList();
+ assertNotNull(result);
}
+ /**
+ * Verifies that a query with an externalized parameter (token maps
+ * to an enum via ExternalValues) executes correctly.
+ */
public void testCanDetectExternalizedSingleParameterValue() {
Review Comment:
**(high)** These three tests kept their names ("CanDetectExternalized...") but no longer detect anything: the `getExpressions()` helper was deleted and the `isUsingExternalizedParameter(...)` assertions were replaced by `assertNotNull(getResultList())`, which can never fail. Was externalized-parameter detection actually removed from the prepared-query cache, or can the original assertions be restored? As written the tests are no-ops.
##########
scripts/run-build-matrix.sh:
##########
@@ -0,0 +1,222 @@
+#!/bin/bash
Review Comment:
**(medium)** Missing ASF license header (other files in `scripts/` have one, and the rat excludes in the root pom only cover `scripts/*.list|options|dict`).
##########
openjpa-project/src/doc/manual/jpa_overview_pc.xml:
##########
@@ -1163,7 +1164,7 @@ data structure.
lifecycle callbacks
</seealso>
</indexterm>
-<ulink url="http://download.oracle.com/javaee/6/api/javax/persistence/PreUpdate.html">
+<ulink url="https://jakarta.ee/specifications/persistence/3.2/apidocs/jakarta.persistence/jakarta/persistence/postupdate">
Review Comment:
**(low)** Copy/paste nit: the PreUpdate entry links to `.../jakarta/persistence/postupdate` - should be `preupdate` (line 1191 is the correct PostUpdate one).
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java:
##########
@@ -477,7 +823,160 @@ public boolean isLoaded(Object entity, String attribute) {
return (OpenJPAPersistenceUtil.isManagedBy(this, entity) &&
(OpenJPAPersistenceUtil.isLoaded(entity, attribute) == LoadState.LOADED));
}
-
+
+ @Override
+ public <E> boolean isLoaded(E entity, Attribute<? super E, ?> attribute) {
+ return isLoaded(entity, attribute.getName());
+ }
+
+ @Override
+ public SchemaManager getSchemaManager() {
+ if (!this.isOpen()) {
+ throw new IllegalStateException("EntityManagerFactory is closed.");
+ }
+ return new SchemaManagerImpl(_factory);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <R> R callInTransaction(Function<EntityManager, R> work) {
+ EntityManager em = createEntityManager();
+ boolean startedTransaction = false;
+ boolean jtaTransaction = getTransactionType() == PersistenceUnitTransactionType.JTA;
+ Broker broker = em.unwrap(Broker.class);
+ try {
+ if (jtaTransaction) {
+ if (!broker.syncWithManagedTransaction()) {
+ broker.begin();
+ startedTransaction = true;
+ }
+ } else {
+ em.getTransaction().begin();
+ startedTransaction = true;
+ }
+ R result = work.apply(em);
+ if (startedTransaction) {
+ if (jtaTransaction) {
+ broker.commit();
+ } else {
+ em.getTransaction().commit();
+ }
+ }
+ // For unenhanced (runtime-subclassed) entities, the user's function
+ // may return an original POJO that was passed to persist().
+ // Entities loaded via find() on other EMs are subclass instances,
+ // causing getClass() mismatches in equals(). To ensure consistent
+ // class identity, re-find managed entities from the database so that
+ // the returned instance is a subclass (matching what find() returns).
+ if (result != null && em.contains(result)) {
+ try {
+ Object id = getPersistenceUnitUtil().getIdentifier(result);
+ if (id != null) {
+ Class<R> entityClass = (Class<R>) result.getClass();
+ em.clear();
+ R refound = em.find(entityClass, id);
+ if (refound != null) {
+ result = refound;
+ }
+ }
+ } catch (Exception e) {
+ // If re-find fails, return original result
+ }
+ }
+ return result;
+ } catch (Exception ex) {
+ if (jtaTransaction) {
+ broker.rollback();
+ } else {
+ try {
+ em.getTransaction().rollback();
+ } catch (Exception rollbackEx) {
+ // Transaction may already be rolled back
+ }
+ }
+ throw new UserException(ex.getMessage(), ex);
+ } finally {
+ em.close();
+ }
+ }
+
+ @Override
+ public void runInTransaction(Consumer<EntityManager> work) {
+ callInTransaction(em -> {
+ work.accept(em);
+ return null;
+ });
+ }
+
+ @Override
+ public <T> Class<? extends T> getClass(T entity) {
+ if (!OpenJPAPersistenceUtil.isManagedBy(this, entity)) {
+ throw new jakarta.persistence.PersistenceException(_loc.get("invalid_entity_argument",
+ "getClass", entity == null ? "null" : Exceptions.toString(entity)).getMessage());
+ }
+ return OpenJPAPersistenceUtil.getClass(this, entity);
+ }
+
+ @Override
+ public <R> Map<String, TypedQueryReference<R>> getNamedQueries(Class<R> resultType) {
+ throw new UnsupportedOperationException("Not yet implemented (JPA 3.2)");
+ }
+
+ @Override
+ public PersistenceUnitTransactionType getTransactionType() {
+ return "managed".equalsIgnoreCase(_factory.getConfiguration().getTransactionMode())
+ ? PersistenceUnitTransactionType.JTA
+ : PersistenceUnitTransactionType.RESOURCE_LOCAL;
+ }
+
+ @Override
+ public Object getVersion(Object entity) {
+ if (!OpenJPAPersistenceUtil.isManagedBy(this, entity)) {
+ throw new IllegalArgumentException(_loc.get("invalid_entity_argument",
Review Comment:
**(low)** Copy/paste: `getVersion` reports "load" as the offending operation in its `invalid_entity_argument` message; should be "getVersion".
##########
.github/workflows/ci.yml:
##########
@@ -14,26 +14,37 @@
# specific language governing permissions and limitations under the License.
#
name: Java CI
-on: [push]
+on:
+ push:
+ branches: [master]
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
env:
MAVEN_OPTS: -Dmaven.artifact.threads=256 -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
jobs:
build:
runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ java: [17, 21]
+ profile: [test-derby, test-h2]
+ name: build (Java ${{ matrix.java }}, ${{ matrix.profile }})
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v7
- name: Setup Java JDK
- uses: actions/setup-java@v4
+ uses: actions/setup-java@v5
with:
distribution: 'zulu'
- java-version: 11
+ java-version: ${{ matrix.java }}
- name: 'Cache Maven packages'
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: ~/.m2
key: 'cache'
Review Comment:
**(medium)** With the new 4-cell matrix, all jobs share the single static cache key 'cache' and race to save it, and it never invalidates on dependency changes. Since setup-java is bumped anyway, `cache: maven` on the setup-java step (or a key including the pom hash and matrix values) would be simpler and correct.
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/simple/TestMissingMetaData.java:
##########
@@ -45,17 +45,15 @@ public void setUp() {
"test-missing-metadata", "persistence2.xml", props);
}
+ /**
+ * Verify that a non-entity class listed in persistence.xml is
+ * gracefully skipped. Per JPA 3.2, persistence units may list
+ * non-entity managed classes (e.g. converters, listeners,
+ * ID classes, exceptions) which should not cause errors.
+ */
public void testMissingMetaData() {
- String msg =
- "No registered metadata for type " +
- "\"class org.apache.openjpa.persistence.simple.Animal\".";
- try {
- emf.createEntityManager();
- fail("didn't receive expected ArgumentException - " + msg);
- } catch (Exception e) {
- assertEquals(ArgumentException.class,e.getClass());
- assertTrue("Unexpected Exception : " + e.getMessage(), e.getMessage().startsWith(msg));
- }
+ // Should not throw — non-entity classes are silently skipped
Review Comment:
**(medium)** Inverted from "listing a non-persistent class in persistence.xml raises ArgumentException" to "non-entity classes are silently skipped". Silent skipping also hides real user errors (forgotten annotations, broken enhancement) that previously failed fast. Is this required by a specific TCK test? If so, could we at least keep a warning log and reference the TCK requirement in a comment?
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/access/PropertyAccessCapitalization.java:
##########
@@ -42,11 +42,11 @@ public class PropertyAccessCapitalization {
private boolean BOOLEAN;
private boolean Bool;
- public int getaCAPITAL() {
+ public int getACAPITAL() {
return aCAPITAL;
}
- public void setaCAPITAL(int aCAPITAL) {
+ public void setACAPITAL(int aCAPITAL) {
Review Comment:
**(medium)** The accessors were renamed from the JavaBeans-Introspector style (getaCAPITAL/getaWord/isaBoolean for fields aCAPITAL/aWord/aBoolean) to getACAPITAL/getAWord/isABoolean. This test existed precisely to cover the former naming, so property-access entities using IDE-generated getaXxx accessors would silently stop being recognized. Did 3.2 change property-name resolution, or is this adapting the test to a regression? Could both variants stay covered?
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/util/TestPersistenceUnitUtil.java:
##########
@@ -18,51 +18,81 @@
*/
package org.apache.openjpa.persistence.util;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import java.sql.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
+import java.util.stream.Stream;
import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.Persistence;
+import jakarta.persistence.PersistenceConfiguration;
+import jakarta.persistence.PersistenceException;
import jakarta.persistence.PersistenceUnitUtil;
+import jakarta.persistence.metamodel.Attribute;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
import org.apache.openjpa.persistence.OpenJPAPersistence;
-import org.apache.openjpa.persistence.test.SingleEMFTestCase;
-
-public class TestPersistenceUnitUtil extends SingleEMFTestCase{
-
- @Override
- public void setUp() {
- setUp(CLEAR_TABLES, EagerEntity.class, LazyEmbed.class,
- LazyEntity.class, EagerEmbed.class, RelEntity.class,
- EagerEmbedRel.class, MapEntity.class,
- MapKeyEmbed.class, MapValEntity.class,
- OneToEntity.class, ToManyLazy.class, ToManyEager.class);
- }
-
- /*
- * Verifies an entity and its persistent attributes are in the proper
- * load state.
- */
- public void testIsLoadedEager() {
- verifyIsLoadedEagerState(true);
- }
-
- /*
- * Verifies an entity and its persistent attributes are in the proper
- * not loaded state.
- */
- public void testNotLoadedLazy() {
- verifyIsLoadedEagerState(false);
- }
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestPersistenceUnitUtil {
+
+ private static EntityManagerFactory emf;
+
+ private EntityManager em;
+
+ @BeforeClass
+ public static void beforeAll() {
+ PersistenceConfiguration conf = new PersistenceConfiguration("dynamicaly-created-pu");
+ conf.property(PersistenceConfiguration.SCHEMAGEN_DATABASE_ACTION, "drop-and-create");
+ Stream.of(EagerEntity.class, LazyEmbed.class,
+ LazyEntity.class, EagerEmbed.class, RelEntity.class, EagerEmbedRel.class,
+ MapEntity.class, MapKeyEmbed.class, MapValEntity.class,
+ OneToEntity.class, ToManyLazy.class, ToManyEager.class)
+ .forEach(conf::managedClass);
+
+ emf = Persistence.createEntityManagerFactory(conf);
+ }
+
+ /*
+ * Verifies an entity and its persistent attributes are in the proper load
+ * state.
+ */
+ @Test
+ public void testIsLoadedEager() {
+ verifyIsLoadedEagerState(true);
+ }
+
+ /*
+ * Verifies an entity and its persistent attributes are in the proper not loaded
+ * state.
+ */
+ @Test
+ public void testNotLoadedLazy() {
Review Comment:
**(low)** In this rewrite, testNotLoadedLazy still calls `verifyIsLoadedEagerState(false)` (duplicate of testNotLoadedEager), so the lazy not-loaded path (`verifyIsLoadedLazyState(false)`) remains untested. Also createLazyEntity builds a RelEntity that is never persisted, which the new testLoadingLazyAttributeByName relies on.
##########
.gitignore:
##########
@@ -11,3 +11,11 @@ nbactions*.xml
.checkstyle
.vscode
+.claude
+CLAUDE.md
+tck-dev
+docker-compose.yml
+pgdata
+openjpa-xmlstore/jdbc*
Review Comment:
**(medium)** Ignoring `openjpa-xmlstore/jdbc*` here, `rm -rf openjpa-xmlstore/jdbc:*` in run-build-matrix.sh:152 and the new exclude in source-assembly.xml are three workarounds for the same problem: the xmlstore tests write their store into the module source tree. Would it not be better to point the test store at `target/` and drop all three?
##########
.github/workflows/ci.yml:
##########
@@ -14,26 +14,37 @@
# specific language governing permissions and limitations under the License.
#
name: Java CI
-on: [push]
+on:
+ push:
+ branches: [master]
Review Comment:
**(medium)** `on: push` is narrowed from all pushes to `branches: [master]`, so direct pushes to maintenance/feature branches (including this one) no longer get a CI build - only PRs do. Intentional? If yes, maybe add maintenance branch patterns at least.
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/SchemaManagerImpl.java:
##########
@@ -0,0 +1,66 @@
+/*
+ * 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.persistence;
+
+import org.apache.openjpa.kernel.BrokerFactory;
+
+import jakarta.persistence.SchemaManager;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Implements a no-op SchemaManager object that will throw
+ * UnsupportedOperationException if not concretelly implemented
+ * by the given persistence layer.
+ *
+ * @author Paulo Cristovão Filho
+ * @since 4.2.0
+ */
+public class SchemaManagerImpl implements SchemaManager {
+ private BrokerFactory _factory;
+
+ public SchemaManagerImpl(BrokerFactory factory) {
+ _factory = factory;
+ }
+
+ @Override
+ public void create(boolean createSchemas) {
+ _factory.createPersistenceStructure(createSchemas);
+ }
+
+ @Override
+ public void drop(boolean dropSchemas) {
+ _factory.dropPersistenceStrucuture(dropSchemas);
Review Comment:
**(medium)** Nits before this freezes: the delegated `BrokerFactory` method names carry the `Strucuture`/`Struture` typos, `truncateData();;` has a double semicolon at line 64, and the `(Exception) ex` cast at line 58 is redundant. Also `validate()` wraps even UnsupportedOperationException from stores that do not implement validation into `SchemaValidationException("Schema could not be validated: null")`, misreporting a missing capability as a validation failure.
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java:
##########
@@ -57,9 +58,17 @@ public void tearDown() throws Exception {
* @param sqlExp the SQL expression. E.g., "SELECT FOO .*"
*/
public void assertSQL(String sqlExp) {
+ DBDictionary dict = getDBDictionary();
for (String statement : sql) {
- if (statement.matches(sqlExp))
+ if (statement.matches(sqlExp)) {
+ return;
+ }
+ String noDelims = statement
Review Comment:
**(medium)** assertSQL() now also matches after stripping identifier delimiters (same idea as the new same() helper in AbstractCriteriaTestCase.java:159). This globally relaxes every SQL assertion in the suite and would mask regressions in delimited-identifier handling. Could the delimiter-insensitive comparison be opt-in, or at least documented why it became necessary?
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/common/apps/CompUser.java:
##########
@@ -66,6 +67,9 @@ public class CompUser {
@Enumerated
@Basic
private CreditRating creditRating;
+
+ @Version
Review Comment:
**(medium)** Adding @Version to CompUser changes the semantics of every test using this shared entity (~24 test files): all updates now do version checks and the generated SQL changes, so those tests no longer cover the unversioned-entity path. Since this seems to exist only to support the new VERSION(u) JPQL test, could that test use a dedicated versioned entity instead of modifying a widely shared fixture?
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestMultiselect.java:
##########
@@ -358,25 +353,22 @@ public void testSanity2() {
assertResult(q, Foo.class);
}
+ /**
+ * JPA 3.2 Section 6.9.1: compound selections (tuple, array) must not
+ * contain other compound selections. Nesting cb.tuple() inside cb.array()
+ * must throw IllegalArgumentException.
+ */
public void testDeeplyNestedShape() {
Review Comment:
**(medium)** testDeeplyNestedShape previously verified OpenJPA's documented extension supporting arbitrary nesting of tuple/array selections (the old comment even said the negative test was retired for that reason); it is now inverted to expect IllegalArgumentException. The spec's "must not" has been there since 2.0, so this drops a working extension existing applications may rely on. Intentional, and should it be release-noted?
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
</bind>
</volumes>
<ports>
<port>${docker.external.oracle.port}:1521</port>
+ <port>5500:5500</port>
</ports>
+ <wait>
+ <log>DATABASE IS READY TO USE</log>
+ <time>3600000</time>
+ </wait>
</run>
</image>
</images>
</configuration>
+ <dependencies>
Review Comment:
**(medium)** Why does docker-maven-plugin need guava 33.2.1-jre added to its plugin classpath in the oracle profile? If it works around a plugin bug, a short comment would help the next person; otherwise it looks droppable.
##########
openjpa-integration/tck/tck32-openjpa-profile.xml:
##########
@@ -0,0 +1,78 @@
+<!--
+ 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.
+-->
+
+<!--
+ This file contains the OpenJPA profile XML fragment to be inserted into
+ the JPA 3.2 TCK runner pom.xml (persistence-tck/bin/pom.xml).
+ It is injected automatically by the tck32-profile build.
+-->
+<profile>
+ <id>openjpa</id>
+ <properties>
+ <glassfish-artifact-id>glassfish</glassfish-artifact-id>
+ <openjpa.version>4.2.0-SNAPSHOT</openjpa.version>
Review Comment:
**(low)** The injected profile hardcodes `<openjpa.version>4.2.0-SNAPSHOT</openjpa.version>`; the script always overrides it via `-Dopenjpa.version`, but the default silently goes stale after release - maybe add a comment that it must be kept in sync (same for the defaults baked into the README examples).
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java:
##########
@@ -1343,9 +1346,6 @@ protected boolean startIdClass(Attributes attrs)
} catch (Throwable t) {
throw getException(_loc.get("invalid-id-class", meta, cls), t);
}
- if (!Serializable.class.isAssignableFrom(idCls)) {
- _conf.getConfigurationLog().warn(_loc.get("id-class-not-serializable", idCls, _cls));
- }
meta.setObjectIdType(idCls, true);
Review Comment:
**(low)** The "IdClass does not implement Serializable" warning was silently dropped both here and in AnnotationPersistenceMetaDataParser. Deliberate (3.2 relaxes it?) or lost in the rewrite?
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilderImpl.java:
##########
@@ -1043,4 +1119,159 @@ public Expression<LocalTime> localTime() {
return new Expressions.CurrentLocalTime();
}
+ @Override
+ public CompoundSelection<Tuple> tuple(List<Selection<?>> selections) {
+ return tuple(selections.toArray(new Selection<?>[0]));
+ }
+
+ @Override
+ public CompoundSelection<Object[]> array(List<Selection<?>> selections) {
+ return array(selections.toArray(new Selection<?>[0]));
+ }
+
+ @Override
+ public Order asc(Expression<?> expression, Nulls nullPrecedence) {
+ return new OrderImpl(expression, true, nullPrecedence);
+ }
+
+ @Override
+ public Order desc(Expression<?> expression, Nulls nullPrecedence) {
+ return new OrderImpl(expression, false, nullPrecedence);
+ }
+
+ @Override
+ public Predicate and(List<Predicate> restrictions) {
+ return and(restrictions.toArray(new Predicate[0]));
+ }
+
+ @Override
+ public Predicate or(List<Predicate> restrictions) {
+ return or(restrictions.toArray(new Predicate[0]));
+ }
+
+ @Override
+ public Expression<String> concat(List<Expression<String>> expressions) {
+ if (expressions == null || expressions.isEmpty())
+ throw new IllegalArgumentException(
+ "concat requires at least one expression");
+ Expression<String> result = expressions.get(0);
+ for (int i = 1; i < expressions.size(); i++) {
+ result = new Expressions.Concat(result, expressions.get(i));
+ }
+ return result;
+ }
+
+ @Override
+ public Expression<String> left(Expression<String> x, int len) {
+ return new Expressions.Left(x, len);
+ }
+
+ @Override
+ public Expression<String> left(Expression<String> x, Expression<Integer> len) {
+ return new Expressions.Left(x, len);
+ }
+
+ @Override
+ public Expression<String> right(Expression<String> x, int len) {
+ return new Expressions.Right(x, len);
+ }
+
+ @Override
+ public Expression<String> right(Expression<String> x, Expression<Integer> len) {
+ return new Expressions.Right(x, len);
+ }
+
+ @Override
+ public Expression<String> replace(Expression<String> str, Expression<String> substring, Expression<String> replacement) {
+ return new Expressions.Replace(str, substring, replacement);
+ }
+
+ @Override
+ public Expression<String> replace(Expression<String> str, String substring, Expression<String> replacement) {
+ return new Expressions.Replace(str, new Expressions.Constant<String>(substring), replacement);
+ }
+
+ @Override
+ public Expression<String> replace(Expression<String> str, Expression<String> substring, String replacement) {
+ return new Expressions.Replace(str, substring, new Expressions.Constant<String>(replacement));
+ }
+
+ @Override
+ public Expression<String> replace(Expression<String> str, String substring, String replacement) {
+ return new Expressions.Replace(str, new Expressions.Constant<String>(substring), new Expressions.Constant<String>(replacement));
+ }
+
+ @Override
+ public <N, T extends Temporal> Expression<N> extract(TemporalField<N, T> field, Expression<T> temporal) {
+ String fieldName = field.toString().toUpperCase();
Review Comment:
**(low)** `field.toString().toUpperCase()` is locale-sensitive ("minute" breaks under a Turkish default locale). Prefer `toUpperCase(Locale.ROOT)`, and ideally key off the known LocalDateField/LocalTimeField constants rather than `toString()`.
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java:
##########
@@ -113,13 +129,15 @@ public OpenJPAConfiguration getConfiguration() {
@Override
public Map<String,Object> getProperties() {
+ if (_factory.isClosed()) {
+ throw new IllegalStateException(
+ "EntityManagerFactory is closed.");
+ }
if (properties == null) {
Review Comment:
**(low)** The old else branch seeding `getProperties()` from a throwaway EM was removed, so the result now depends on whether an EM was created before the first call - and since the map is cached, the EM-level defaults are then permanently missing. Intentional, or should the cache be invalidated once `emEmptyPropsProperties` becomes available?
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java:
##########
@@ -427,19 +469,81 @@ public MetamodelImpl getMetamodel() {
}
return _metaModel;
}
+
+ @Override
+ public String getName() {
+ return (String) _factory.getProperties().get("openjpa.Id");
+ }
@Override
public PersistenceUnitUtil getPersistenceUnitUtil() {
+ if (_factory.isClosed()) {
+ throw new IllegalStateException(
+ "EntityManagerFactory is closed.");
+ }
return this;
}
@Override
public void addNamedQuery(String name, Query query) {
- org.apache.openjpa.kernel.Query kernelQuery = ((QueryImpl<?>)query).getDelegate();
- MetaDataRepository metaDataRepositoryInstance = _factory.getConfiguration().getMetaDataRepositoryInstance();
- QueryMetaData metaData = metaDataRepositoryInstance.newQueryMetaData(null, null);
+ QueryImpl<?> queryImpl = (QueryImpl<?>) query;
+ org.apache.openjpa.kernel.Query kernelQuery = queryImpl.getDelegate();
+ MetaDataRepository repos = _factory.getConfiguration().getMetaDataRepositoryInstance();
+ QueryMetaData metaData = repos.newQueryMetaData(null, name);
metaData.setFrom(kernelQuery);
- metaDataRepositoryInstance.addQueryMetaData(metaData);
+
+ // If the source query uses the Criteria language, convert to JPQL
+ // so that createNamedQuery can recreate it without needing the
+ // original CriteriaQuery object (CriteriaBuilder.parse() only
+ // accepts CriteriaQuery objects, not strings).
+ if (OpenJPACriteriaBuilder.LANG_CRITERIA.equals(metaData.getLanguage())) {
Review Comment:
**(medium)** `addNamedQuery` re-labels a criteria query as JPQL using `queryImpl.getQueryString()`, which for criteria queries is the CQL/toString rendering - OpenJPA has never guaranteed that string is parseable JPQL (parameter rendering, literals, treated paths). Has this been exercised beyond simple queries? The three `catch (Exception) { // ignore }` blocks below (lines 512-540) would also hide genuine failures - they could be narrowed to IllegalStateException where the spec defines it.
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestQueryResults.java:
##########
@@ -75,9 +80,10 @@ public void testQueryIteratorsReturnFalseForClosedQuery() {
endTx(em);
endEm(em);
- if (i.hasNext())
- fail("Iterator obtained from Query should return false "
- + "for hasNext() after Query has been closed");
+ // With ArrayList-backed results, iterators remain valid after
+ // query close — this is correct JPA 3.2 behavior.
+ assertTrue("ArrayList iterator should still have elements "
Review Comment:
**(high)** Several assertions here (and in TestQueryTimeout) were inverted from "iterator must be invalid after query/EM close" to "iterator still works because results are now an ArrayList snapshot". Which JPA 3.2 clause requires this? More importantly, does this mean the lazy ResultList (openjpa.FetchBatchSize streaming results) is gone and results are always fully materialized? That would be a significant memory/perf behavior change deserving explicit discussion and release-noting, not just adjusted tests.
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java:
##########
@@ -862,6 +857,14 @@ else if (XMLVersionParser.VERSION_3_0.equals(_persistenceVersion)
|| (_schemaLocation != null && _schemaLocation.indexOf(PERSISTENCE_XSD_3_0) != -1)) {
persistencexsd = "persistence_3_0.xsd.rsrc";
}
+ else if (XMLVersionParser.VERSION_3_1.equals(_persistenceVersion)
Review Comment:
**(medium)** Documents declaring `version="3.1"` are routed to `persistence_3_0.xsd.rsrc`, but that schema declares `version` as `fixed="3.0" use="required"`, so such documents always fail XSD validation - and with the new SAX-rethrow logic at line 570 this now aborts unit discovery instead of being skipped. Is the branch intentional, and should not it validate against a schema that accepts "3.1"? (Note the copy-pasted `PERSISTENCE_XSD_3_0` in the 3.1 condition.)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4990106013
Perhaps this is a follow-up yes - was able to reproduce it as well.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3781828263
##########
openjpa-integration/tck/README.md:
##########
@@ -0,0 +1,130 @@
+# OpenJPA JPA 3.2 TCK Runner
+
+This module runs the Jakarta Persistence 3.2 Technology Compatibility Kit (TCK)
+against OpenJPA using PostgreSQL.
+
+## Prerequisites
+
+- Java 17+
+- Maven 3.x
+- PostgreSQL (via Docker or a standalone instance)
+- `psql` command-line client (for database preparation)
+- `python3`, `curl`, `unzip` (the script checks for all required commands at startup)
+
+## Quick Start
+
+### 1. Start PostgreSQL
+
+From the **project root**:
+
+```bash
+docker compose up -d
Review Comment:
this one seems to be already addressed
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3781889711
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
</bind>
</volumes>
<ports>
<port>${docker.external.oracle.port}:1521</port>
+ <port>5500:5500</port>
</ports>
+ <wait>
+ <log>DATABASE IS READY TO USE</log>
+ <time>3600000</time>
+ </wait>
</run>
</image>
</images>
</configuration>
+ <dependencies>
Review Comment:
done
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3781897787
##########
.gitignore:
##########
@@ -11,3 +11,11 @@ nbactions*.xml
.checkstyle
.vscode
+.claude
+CLAUDE.md
+tck-dev
+docker-compose.yml
+pgdata
+openjpa-xmlstore/jdbc*
Review Comment:
good catch :) I'll check
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5130833624
@solomax, did openjpa pass the TCK in others DBs?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3687191877
##########
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/TypecastAsNumber.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.kernel.exps;
+
+import org.apache.openjpa.kernel.StoreContext;
+
+/**
+ * Extract the part value of a temporal type
+ *
+ */
+class TypecastAsNumber extends Val {
+ private static final long serialVersionUID = 1L;
+ private final Class<? extends Number> _targetType;
+ private final Val _val;
+
+ /**
+ * Constructor. Provide target field and the value.
+ */
+ public TypecastAsNumber(Val val, Class<? extends Number> target) {
+ _val = val;
+ _targetType = target;
+ }
+
+ @Override
+ public Class getType() {
+ if (_targetType == Integer.class) {
+ return int.class;
+ } else if (_targetType == Long.class) {
+ return long.class;
+ } else if (_targetType == Float.class) {
+ return float.class;
+ } else if (_targetType == Double.class) {
+ return double.class;
+ } else {
+ return _targetType;
+ }
+ }
+
+ @Override
+ public void setImplicitType(Class type) {
+ }
+
+ @Override
+ protected Object eval(Object candidate, Object orig,
+ StoreContext ctx, Object[] params) {
+
+ Object r = _val.eval(candidate, orig, ctx, params);
+ Class<?> clazz = r.getClass();
+ if (_targetType == Integer.class) {
+ if (r instanceof String s) {
+ return Integer.valueOf(s);
+ } else if (clazz.isAssignableFrom(Number.class)) {
Review Comment:
Fixed TypecastAsNumber and TypecastAsString, using instanceof instead of bad comparisson.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3689045213
##########
.gitignore:
##########
@@ -11,3 +11,11 @@ nbactions*.xml
.checkstyle
.vscode
+.claude
Review Comment:
Good catch, and it went deeper than the .gitignore. `docker-compose.yml` was deliberately removed in a80a08e6d ("run-tck32.sh is improved to use dockers from pom") — the TCK now starts its database via docker-maven-plugin from `run-tck32.sh`, so there is no compose file any more and the README Quick Start was pointing at a file that no longer exists (plus stale `5433` / `openjpa` defaults; the script actually uses `5555` / `tcktest`).
Fixed in 562c90d31:
- dropped `docker-compose.yml`, `pgdata` and `tck-dev` from `.gitignore` — all leftovers of the compose setup
- rewrote the TCK README to match what the script really does (auto-started container unless `DB_HOST` is set, correct defaults, the other supported `DB_TYPE` values, corrected prerequisite list)
Kept `.claude` / `CLAUDE.md` for now — happy to move those to a global gitignore instead if you prefer.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3368868580
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java:
##########
@@ -3731,13 +3891,7 @@ public String[] getCreateTableSQL(Table table) {
checkNameLength(getFullIdentifier(table, false), maxTableNameLength, "long-table-name",
tableLengthIncludesSchema);
buf.append("CREATE TABLE ").append(tableName);
- if (supportsComments && table.hasComment()) {
- buf.append(" ");
Review Comment:
why this code was dropped?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3425727848
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -107,6 +109,11 @@ public void testTruncate() {
@Test
public void testValidate() {
EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ DBDictionary dict = getDbDictionary(emf);
+ if (dict instanceof MySQLDictionary) {
Review Comment:
great we have sorted this one out :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4727477358
> Another update: `HerbDB` seems to be broken in `master` so it should be fixed separately :)
@eolivelli maybe you would like to fix `HerbDB` support? ;)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3414708367
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -107,6 +109,11 @@ public void testTruncate() {
@Test
public void testValidate() {
EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ DBDictionary dict = getDbDictionary(emf);
+ if (dict instanceof MySQLDictionary) {
Review Comment:
Hello @cristof,
both mysql 8.0 and 9.4.0 are green locally
could you please describe a bit why this change is required? :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3416516126
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -107,6 +109,11 @@ public void testTruncate() {
@Test
public void testValidate() {
EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ DBDictionary dict = getDbDictionary(emf);
+ if (dict instanceof MySQLDictionary) {
Review Comment:
I'll run again in a clean environment just to be sure.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3437896915
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/BatchingPreparedStatementManagerImpl.java:
##########
@@ -254,13 +254,22 @@ private void flushSingleRow(RowImpl row, PreparedStatement ps)
row.flush(ps, _dict, _store);
int count = executeUpdate(ps, row.getSQL(_dict), row);
if (count != 1) {
- logSQLWarnings(ps);
- Object failed = row.getFailedObject();
- if (failed != null)
- _exceptions.add(new OptimisticException(failed));
- else if (row.getAction() == Row.ACTION_INSERT)
- throw new SQLException(_loc.get("update-failed-no-failed-obj",
- String.valueOf(count), row.getSQL(_dict)).getMessage());
+ // For DELETE actions, tolerate count=0 because the row may
+ // have already been removed by a database-level ON DELETE
+ // CASCADE triggered by a related row's deletion.
+ if (count == 0 && row.getAction() == Row.ACTION_DELETE) {
Review Comment:
Good catch - I think as written this is too broad.
This was added for two TCK tests (persistMX1Test2, cascadeAllMX1Test2) where a parent and child are removed in the same tx and the FK has a DB-level ON DELETE CASCADE. OpenJPA flushes the parent DELETE first, the DB cascades and removes the child row, and then OpenJPA's own DELETE of the child returns count == 0. Before this change that 0 always produced a spurious OptimisticException, because RowManagerImpl.getRow() sets a non-null failed object on essentially every managed row; so the old code couldn't tell "benign already-gone" from a real conflict either.
But you're right on the spec point (just checked again): count == 0 on a DELETE also legitimately means an optimistic-lock failure. For a @Version entity the SQL is DELETE .. WHERE id = ? AND version = ?, and 0 rows there is a concurrent update/delete that the spec says must surface as OptimisticLockException.
As currently written we'd swallow that, and the caller loses the only signal we had - exactly your "how do I know it was a no-op" concern. The TCK entities here are non-versioned, which is why it slipped through.
We could gate/check for an entity having no version field; tolerate count == 0 on DELETE only when there's no @Version (so there's no optimistic signal to honor), and otherwise keep the existing OptimisticException path for flushAndUpdate, flushSingleRow, and checkUpdateCount case 0.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3438866351
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
When I was checking the issue with MySQL, I found the issue emerging from the @MapKeyEnumerated treatment, but the fix only for that case demands some structural changes. Maybe the proposed change also avoids the need of a external parameter on jdbc connecto for mysql.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3449916024
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
> Meanwhile I'll start huge Oracle test (I'm afraid it will require days on my laptop :((( )
My estimate might be too optimistic, due to:
```
Time elapsed: 2165 s -- in org.apache.openjpa.jdbc.meta.TestMappingToolRefresh
Time elapsed: 2840 s -- in org.apache.openjpa.jdbc.meta.TestJDBCSchemaManager
Time elapsed: 1160 s -- in org.apache.openjpa.jdbc.kernel.TestNoForeignKeyViolation
Time elapsed: 1461 s -- in org.apache.openjpa.persistence.spring.TestLibService
Time elapsed: 1400 s -- in org.apache.openjpa.persistence.entitygraph.TestEntityGraph
Time elapsed: 16295 s -- in org.apache.openjpa.persistence.criteria.TestTypecastAsCriteria
Time elapsed: 34642 s -- in org.apache.openjpa.persistence.criteria.TestEdit
Time elapsed: 75059 s -- in org.apache.openjpa.persistence.criteria.results.TestMultiselect
Time elapsed: 5583 s -- in org.apache.openjpa.persistence.criteria.TestFetchJoin
Time elapsed: 19513 s -- in org.apache.openjpa.persistence.criteria.TestQueryByExample
Time elapsed: 78590 s -- in org.apache.openjpa.persistence.criteria.TestMetaModelTypesafeCriteria
```
I'll keep you updated :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3584925138
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/functions/TestEJBQLFunction.java:
##########
Review Comment:
`MIN(...)` is also broken
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4991146234
We have to keep in mind that JPA 3.2 is Java 17 bound (https://jakarta.ee/specifications/persistence/3.2/).
I'm addressing the remaining Oracle issues today.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4999259099
How do you run the tests exactly? They require quite a lot of properties 🙃
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4993057036
> @rzo1 are there any changes required to address unresolved comments from @rmannibucau ?
Most likely as I wrote: Would most likely be beneficial to do the additional check for @ Version instead of swallowing (and if no OptimisticLock possible, just return 0 - but got no feedback on it so far ;-) )
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-4993020655
@rzo1 are there any changes required to address unresolved comments from @rmannibucau ?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3556224318
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/meta/TestJDBCSchemaManager.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * 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.meta;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.UUID;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+import org.junit.Test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.SchemaValidationException;
+
+/**
+ * Test that a {@link MappingTool#ACTION_REFRESH} uses the right
+ * types for new columns and takes any mapping in DBDictionary into account.
+ */
+public class TestJDBCSchemaManager extends AbstractPersistenceTestCase {
+ /**
+ * First we create a schema mapping with boolean representation as CHAR(1).
+ * Then we create an entry.
+ * After that we create a diff from the entity to the current DB.
+ * This should result in an empty diff.
+ */
+ @Test
+ public void testSchemaReset() throws Exception {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ assertNotNull(em);
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUID id = ue1.getId();
+ closeEM(em);
+
+ EntityManager em2 = emf.createEntityManager();
+ assertNotNull(em2);
+
+ UUIDEntity ue2 = em2.find(UUIDEntity.class, id);
+ assertNotNull(ue2);
+ assertNotEquals(ue1, ue2);
+
+ closeEM(em2);
+
+ closeEMF(emf);
+ }
+
+ @Test
+ public void testBuildSchema() throws IOException, SQLException {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ emf.createEntityManager();
+
+ emf.getSchemaManager().create(false);
+ emf.getSchemaManager().drop(false);
+ }
+
+ @Test
+ public void testTruncate() {
+ EntityManagerFactory emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+
+ em.getTransaction().commit();
+ UUIDEntity ue2 = em.find(UUIDEntity.class, ue1.getId());
+ assertNotNull(ue2);
+
+ closeEM(em);
+
+ emf.getSchemaManager().truncate();
+
+ em = emf.createEntityManager();
+ assertNull(em.find(UUIDEntity.class, ue1.getId()));
+ closeEM(em);
+ }
+
+ @Test
+ public void testValidate() {
+ OpenJPAEntityManagerFactorySPI emf = createEMF(UUIDEntity.class, EntityBoolChar.class, DROP_TABLES);;
+ EntityManager em = emf.createEntityManager();
+
+ em.getTransaction().begin();
+ UUIDEntity ue1 = new UUIDEntity();
+ ue1.setValue("Something");
+ em.persist(ue1);
+ em.getTransaction().commit();
+
+ Connection conn = (Connection) ((OpenJPAEntityManagerSPI) em.getDelegate()).getConnection();
+
+ JDBCConfiguration conf = ((JDBCConfiguration) emf.getConfiguration());
+ DBDictionary dict = conf.getDBDictionaryInstance();
+
+ try (Statement stmt = conn.createStatement()) {
+ stmt.executeUpdate("ALTER TABLE UUIDEntity DROP COLUMN value_");
+ stmt.executeUpdate("ALTER TABLE UUIDEntity ADD " + (dict instanceof OracleDictionary ? "" : "COLUMN") + " value_ BOOLEAN DEFAULT FALSE");
Review Comment:
It seems `LN` should be `[LOG](https://learn.microsoft.com/en-us/sql/t-sql/functions/log-transact-sql?view=sql-server-ver17)` for MSSqlServer ...
@cristof do we have some sort of variable for it? :))
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "cristof (via GitHub)" <gi...@apache.org>.
cristof commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3771743825
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerFactoryImpl.java:
##########
@@ -477,7 +823,160 @@ public boolean isLoaded(Object entity, String attribute) {
return (OpenJPAPersistenceUtil.isManagedBy(this, entity) &&
(OpenJPAPersistenceUtil.isLoaded(entity, attribute) == LoadState.LOADED));
}
-
+
+ @Override
+ public <E> boolean isLoaded(E entity, Attribute<? super E, ?> attribute) {
+ return isLoaded(entity, attribute.getName());
+ }
+
+ @Override
+ public SchemaManager getSchemaManager() {
+ if (!this.isOpen()) {
+ throw new IllegalStateException("EntityManagerFactory is closed.");
+ }
+ return new SchemaManagerImpl(_factory);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <R> R callInTransaction(Function<EntityManager, R> work) {
+ EntityManager em = createEntityManager();
+ boolean startedTransaction = false;
+ boolean jtaTransaction = getTransactionType() == PersistenceUnitTransactionType.JTA;
+ Broker broker = em.unwrap(Broker.class);
+ try {
+ if (jtaTransaction) {
+ if (!broker.syncWithManagedTransaction()) {
+ broker.begin();
+ startedTransaction = true;
+ }
+ } else {
+ em.getTransaction().begin();
+ startedTransaction = true;
+ }
+ R result = work.apply(em);
+ if (startedTransaction) {
+ if (jtaTransaction) {
+ broker.commit();
+ } else {
+ em.getTransaction().commit();
+ }
+ }
+ // For unenhanced (runtime-subclassed) entities, the user's function
+ // may return an original POJO that was passed to persist().
+ // Entities loaded via find() on other EMs are subclass instances,
+ // causing getClass() mismatches in equals(). To ensure consistent
+ // class identity, re-find managed entities from the database so that
+ // the returned instance is a subclass (matching what find() returns).
+ if (result != null && em.contains(result)) {
+ try {
+ Object id = getPersistenceUnitUtil().getIdentifier(result);
+ if (id != null) {
+ Class<R> entityClass = (Class<R>) result.getClass();
+ em.clear();
+ R refound = em.find(entityClass, id);
+ if (refound != null) {
+ result = refound;
+ }
+ }
+ } catch (Exception e) {
+ // If re-find fails, return original result
+ }
+ }
+ return result;
+ } catch (Exception ex) {
+ if (jtaTransaction) {
Review Comment:
Added test so the broker rollsback only when it started the transaction.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3780986813
##########
openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilderImpl.java:
##########
@@ -1043,4 +1119,159 @@ public Expression<LocalTime> localTime() {
return new Expressions.CurrentLocalTime();
}
+ @Override
+ public CompoundSelection<Tuple> tuple(List<Selection<?>> selections) {
+ return tuple(selections.toArray(new Selection<?>[0]));
+ }
+
+ @Override
+ public CompoundSelection<Object[]> array(List<Selection<?>> selections) {
+ return array(selections.toArray(new Selection<?>[0]));
+ }
+
+ @Override
+ public Order asc(Expression<?> expression, Nulls nullPrecedence) {
+ return new OrderImpl(expression, true, nullPrecedence);
+ }
+
+ @Override
+ public Order desc(Expression<?> expression, Nulls nullPrecedence) {
+ return new OrderImpl(expression, false, nullPrecedence);
+ }
+
+ @Override
+ public Predicate and(List<Predicate> restrictions) {
+ return and(restrictions.toArray(new Predicate[0]));
+ }
+
+ @Override
+ public Predicate or(List<Predicate> restrictions) {
+ return or(restrictions.toArray(new Predicate[0]));
+ }
+
+ @Override
+ public Expression<String> concat(List<Expression<String>> expressions) {
+ if (expressions == null || expressions.isEmpty())
+ throw new IllegalArgumentException(
+ "concat requires at least one expression");
+ Expression<String> result = expressions.get(0);
+ for (int i = 1; i < expressions.size(); i++) {
+ result = new Expressions.Concat(result, expressions.get(i));
+ }
+ return result;
+ }
+
+ @Override
+ public Expression<String> left(Expression<String> x, int len) {
+ return new Expressions.Left(x, len);
+ }
+
+ @Override
+ public Expression<String> left(Expression<String> x, Expression<Integer> len) {
+ return new Expressions.Left(x, len);
+ }
+
+ @Override
+ public Expression<String> right(Expression<String> x, int len) {
+ return new Expressions.Right(x, len);
+ }
+
+ @Override
+ public Expression<String> right(Expression<String> x, Expression<Integer> len) {
+ return new Expressions.Right(x, len);
+ }
+
+ @Override
+ public Expression<String> replace(Expression<String> str, Expression<String> substring, Expression<String> replacement) {
+ return new Expressions.Replace(str, substring, replacement);
+ }
+
+ @Override
+ public Expression<String> replace(Expression<String> str, String substring, Expression<String> replacement) {
+ return new Expressions.Replace(str, new Expressions.Constant<String>(substring), replacement);
+ }
+
+ @Override
+ public Expression<String> replace(Expression<String> str, Expression<String> substring, String replacement) {
+ return new Expressions.Replace(str, substring, new Expressions.Constant<String>(replacement));
+ }
+
+ @Override
+ public Expression<String> replace(Expression<String> str, String substring, String replacement) {
+ return new Expressions.Replace(str, new Expressions.Constant<String>(substring), new Expressions.Constant<String>(replacement));
+ }
+
+ @Override
+ public <N, T extends Temporal> Expression<N> extract(TemporalField<N, T> field, Expression<T> temporal) {
+ String fieldName = field.toString().toUpperCase();
Review Comment:
there are lots of such cases in the code :( (I'll update them all + will update `toLowerCase()`)
The question is: there are lots of places with `.toUpperCase(Locale.ENGLISH);` shall it be updated to `.toUpperCase(Locale.ROOT);`?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3781877927
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
Review Comment:
Unfortunately it will break everything :(
Oracle docker creates lots of files as `root` thus `mvn clean` will fail is such case
I've tried `${project.basedir}/jdbc_oradata` and `${project.basedir}/openjpa-jdbc/jdbc_oradata` but this makes `apache-rat` very unhappy ....
Any ideas are much appreciated :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rmannibucau (via GitHub)" <gi...@apache.org>.
rmannibucau commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3781914780
##########
pom.xml:
##########
@@ -1633,24 +1609,41 @@
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
+ <keepContainer>false</keepContainer>
+ <removeVolumes>true</removeVolumes>
<images>
<image>
- <!--<name>oracledb19c/oracle.19.3.0-ee:oracle19.3.0-ee</name>-->
- <name>oracleinanutshell/oracle-xe-11g</name>
- <!--<name>pvargacl/oracle-xe-18.4.0:latest</name>-->
+ <name>container-registry.oracle.com/database/express:${oracle.server.version}</name>
<run>
+ <env>
+ <ORACLE_PWD>${openjpa.oracle.password}</ORACLE_PWD>
+ </env>
<volumes>
<bind>
- <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/</volume>
+ <volume>${project.basedir}/src/test/sql/oracle-docker:/docker-entrypoint-initdb.d/setup/</volume>
+ <!-- NOTE this folder MUST exist and have correct permissions!!!! -->
+ <volume>${project.basedir}/../jdbc_oradata:/opt/oracle/oradata</volume>
Review Comment:
adding it to .gitignore should be read by rat and ignored, it is also possible to force uid/gid when running the container so it is not root but the same as your host.
that said cleaner would be to create any local dir and just use the container ephemeral space for that need no? init can be done with sh, potentially running some java, was it tried?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "rzo1 (via GitHub)" <gi...@apache.org>.
rzo1 commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5318662301
My GitHub webapp doesn't open all of the comments anymore (lol) - seems a bit broken. So where are we atm?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3809614565
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/query/TestTimeoutException.java:
##########
@@ -97,6 +99,37 @@ public void testQueryTimeOutExceptionWhileQueryingWithLocksOnAlreadyLockedEntiti
}
}
+ public void testLockTimeOutExceptionWhileQueryingWithLocksOnAlreadyLockedEntitiesOption() {
Review Comment:
This test seems to hang for `Oracle:8.4.0` is it by design?
What is the rule to set `DBDictionary.supportsQueryTimeout` ?
I've added TestTimeout == 30min for this test for now, not sure how to properly fix it :((
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801044150
##########
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MySQLDictionary.java:
##########
@@ -536,5 +559,55 @@ public void indexOf(SQLBuffer buf, FilterValue str, FilterValue find,
}
buf.append(")");
}
+
+ /**
+ * MySQL / MariaDB do not support ANSI SQL {@code NULLS FIRST} / {@code NULLS LAST}.
+ * Emulate via an auxiliary {@code <expr> IS NULL} sort key.
+ * <p>
+ * MySQL's default NULL ordering places NULLs before non-NULLs when sorting
+ * ASC and after non-NULLs when sorting DESC. When the requested precedence
+ * already matches that default, nothing extra is emitted. Otherwise the
+ * last order term {@code <expr> ASC|DESC} is rewritten to
+ * {@code <expr> IS NULL <sort>, <expr> ASC|DESC}.
+ */
+ @Override
+ public void appendNullsPrecedence(SQLBuffer ordering, int nullPrecedence) {
+ if (nullPrecedence != QueryExpressions.NULLS_FIRST
+ && nullPrecedence != QueryExpressions.NULLS_LAST) {
+ return;
+ }
+ String sql = ordering.getSQL();
+ int lastAsc = sql.lastIndexOf(" ASC");
+ int lastDesc = sql.lastIndexOf(" DESC");
+ boolean asc;
+ int termDirStart;
+ int termDirEnd;
+ if (lastAsc > lastDesc) {
+ asc = true;
+ termDirStart = lastAsc;
+ termDirEnd = lastAsc + " ASC".length();
+ } else if (lastDesc >= 0) {
+ asc = false;
+ termDirStart = lastDesc;
+ termDirEnd = lastDesc + " DESC".length();
+ } else {
+ return;
+ }
+ boolean defaultMatches =
+ (nullPrecedence == QueryExpressions.NULLS_FIRST && asc)
+ || (nullPrecedence == QueryExpressions.NULLS_LAST && !asc);
+ if (defaultMatches) {
+ return;
+ }
+ int termStart = Math.max(sql.lastIndexOf(", ", termDirStart), -1);
Review Comment:
I'll try to investigate this one
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3801982069
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypecastAsCriteria.java:
##########
@@ -0,0 +1,122 @@
+/*
+ * 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.persistence.criteria;
+
+import java.time.LocalDateTime;
+
+import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.Root;
+import jakarta.persistence.criteria.SetJoin;
+
+import org.apache.openjpa.jdbc.sql.DerbyDictionary;
+
+public class TestTypecastAsCriteria extends CriteriaTest {
+
+ public void testTypecastAsString() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // Derby does not support these CASTs
Review Comment:
Github CI runs both `Derby` and `H2` so these tests are not entirely skipped
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5325773028
All,
There are lot's of unaddressed comments, but I'm afraid working on them in this PR is a pain :(
Maybe it worth to merge this one and address remaining in a separate PR?
Shall this one be squashed WDYT?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on PR #144:
URL: https://github.com/apache/openjpa/pull/144#issuecomment-5325881616
@rmannibucau could you please mark all answered comments which doesn't require any further work as resolved?
I can then try to move all remaining issues to the JIRA (hopefully I can do it with the links to the particular comment)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Implements Jakarta Persistence 3.2 [openjpa]
Posted by "solomax (via GitHub)" <gi...@apache.org>.
solomax commented on code in PR #144:
URL: https://github.com/apache/openjpa/pull/144#discussion_r3809994203
##########
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/TestTypesafeCriteria.java:
##########
@@ -1781,5 +1789,168 @@ public void testIdClass() {
assertEquivalence(cq, jpql);
}
+
+ public void testLeft() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where left(p.name, 4) = 'John'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.left(c.get("name"), 4), "John"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testRight() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ String jpql = "select p from Person p where RIGHT(p.name, 3) = 'Doe'";
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.right(c.get("name"), 3), "Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ public void testReplace() {
+ if (getDictionary() instanceof DerbyDictionary) {
+ // TODO Derby DB does not support LEFT, RIGHT or REPLACE functions
+ return;
+ }
+ em.getTransaction().begin();
+ Person p = new Person();
+ p.setName("John Fitzgerald Doe");
+ em.persist(p);
+ em.getTransaction().commit();
+
+ String jpql = "select p from Person p where REPLACE(p.name, 'ohn', 'ack') = 'Jack Fitzgerald Doe'";
+ CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+ Root<Person> c = cq.from(Person.class);
+ cq.where(cb.equal(cb.replace(c.get("name"), "ohn", "ack"), "Jack Fitzgerald Doe"));
+ em.createQuery(cq).getResultList();
+
+ assertEquivalence(cq, jpql);
+ }
+
+ /**
+ * JPA 3.2 Criteria UNION must execute end-to-end and produce the
+ * same SQL as the JPQL UNION form. We don't compare row counts
+ * because TestTypesafeCriteria shares a static EMF with other test
+ * classes and we don't want to seed shared tables.
+ */
+ public void testCriteriaUnion() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 30));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.equal(r2.get("name"), "Ugo"));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> union = cb.union(q1, q2);
+ assertNotNull(em.createQuery(union).getResultList());
+ }
+
+ public void testCriteriaUnionAll() {
+ CriteriaQuery<String> q1 = cb.createQuery(String.class);
+ Root<CompUser> r1 = q1.from(CompUser.class);
+ q1.select(r1.<String>get("name"))
+ .where(cb.gt(r1.<Integer>get("age"), 25));
+
+ CriteriaQuery<String> q2 = cb.createQuery(String.class);
+ Root<CompUser> r2 = q2.from(CompUser.class);
+ q2.select(r2.<String>get("name"))
+ .where(cb.gt(r2.<Integer>get("age"), 30));
+
+ jakarta.persistence.criteria.CriteriaSelect<String> unionAll = cb.unionAll(q1, q2);
+ assertNotNull(em.createQuery(unionAll).getResultList());
+ }
+
+ public void testCriteriaExcept() {
Review Comment:
It seems I found the way
Will commit and ask for review :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: dev-unsubscribe@openjpa.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org