Added missing EXTRACT(QUARTER FROM date/datetime) for Derby platform. Covered EXTRACT queries with jUnit.
Signed-off-by: Tomas Kraus <tomas.kraus@oracle.com>
diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/platform/database/DerbyPlatform.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/platform/database/DerbyPlatform.java
index 2259854..5eec658 100644
--- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/platform/database/DerbyPlatform.java
+++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/platform/database/DerbyPlatform.java
@@ -32,6 +32,7 @@
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
import java.util.Vector;
import org.eclipse.persistence.exceptions.ValidationException;
@@ -41,6 +42,7 @@
import org.eclipse.persistence.internal.databaseaccess.FieldTypeDefinition;
import org.eclipse.persistence.internal.expressions.ExpressionJavaPrinter;
import org.eclipse.persistence.internal.expressions.ExpressionSQLPrinter;
+import org.eclipse.persistence.internal.expressions.LiteralExpression;
import org.eclipse.persistence.internal.expressions.SQLSelectStatement;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.internal.helper.DatabaseField;
@@ -345,7 +347,7 @@
addOperator(ExpressionOperator.simpleFunction(ExpressionOperator.ToNumber, "DOUBLE"));
// LocalTime should be processed as TIMESTAMP
addOperator(ExpressionOperator.simpleFunctionNoParentheses(ExpressionOperator.LocalTime, "CAST(CURRENT_TIME AS TIMESTAMP)"));
- addOperator(extractOperator());
+ addOperator(derbyExtractOperator());
addOperator(derbyPowerOperator());
addOperator(derbyRoundOperator());
}
@@ -495,12 +497,74 @@
* INTERNAL:
* Derby does not support EXTRACT, but does have YEAR, MONTH, DAY, etc.
*/
- public static ExpressionOperator extractOperator() {
- ExpressionOperator exOperator = new ExpressionOperator();
+ public static ExpressionOperator derbyExtractOperator() {
+
+ ExpressionOperator exOperator = new ExpressionOperator() {
+
+ // QUARTER emulation: ((MONTH(:first)+2)/3)
+ private final String[] QUARTER_STRINGS = new String[] {"((MONTH(", ")+2)/3)"};
+
+ private void printQuarterSQL(final Expression first, final ExpressionSQLPrinter printer) {
+ printer.printString(QUARTER_STRINGS[0]);
+ first.printSQL(printer);
+ printer.printString(QUARTER_STRINGS[1]);
+ }
+
+ private void printQuarterJava(final Expression first, final ExpressionJavaPrinter printer) {
+ printer.printString(QUARTER_STRINGS[0]);
+ first.printJava(printer);
+ printer.printString(QUARTER_STRINGS[1]);
+ }
+
+ @Override
+ public void printDuo(Expression first, Expression second, ExpressionSQLPrinter printer) {
+ if (second instanceof LiteralExpression && "QUARTER".equals(((LiteralExpression)second).getValue().toUpperCase())) {
+ printQuarterSQL(first, printer);
+ } else {
+ super.printDuo(first, second, printer);
+ }
+ }
+
+ @Override
+ public void printCollection(List items, ExpressionSQLPrinter printer) {
+ if (items.size() == 2) {
+ Expression first = (Expression)items.get(0);
+ Expression second = (Expression)items.get(1);
+ if (second instanceof LiteralExpression && "QUARTER".equals(((LiteralExpression)second).getValue().toUpperCase())) {
+ printQuarterSQL(first, printer);
+ return;
+ }
+ }
+ super.printCollection(items, printer);
+ }
+
+ @Override
+ public void printJavaDuo(Expression first, Expression second, ExpressionJavaPrinter printer) {
+ if (second instanceof LiteralExpression && "QUARTER".equals(((LiteralExpression)second).getValue().toUpperCase())) {
+ printQuarterJava(first, printer);
+ } else {
+ super.printJavaDuo(first, second, printer);
+ }
+ }
+
+ @Override
+ public void printJavaCollection(List items, ExpressionJavaPrinter printer) {
+ if (items.size() == 2) {
+ Expression first = (Expression)items.get(0);
+ Expression second = (Expression)items.get(1);
+ if (second instanceof LiteralExpression && "QUARTER".equals(((LiteralExpression)second).getValue().toUpperCase())) {
+ printQuarterJava(first, printer);
+ return;
+ }
+ }
+ super.printJavaCollection(items, printer);
+ }
+ };
+
exOperator.setType(ExpressionOperator.FunctionOperator);
exOperator.setSelector(ExpressionOperator.Extract);
exOperator.setName("EXTRACT");
- List<String> v = new ArrayList<>(5);
+ List<String> v = new ArrayList<>(3);
v.add("");
v.add("(");
v.add(")");
diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/criteria/model/TestDateTimeFunctions.java b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/criteria/TestDateTimeFunctions.java
similarity index 95%
rename from jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/criteria/model/TestDateTimeFunctions.java
rename to jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/criteria/TestDateTimeFunctions.java
index 85d7fc0..d48bd9a 100644
--- a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/criteria/model/TestDateTimeFunctions.java
+++ b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/criteria/TestDateTimeFunctions.java
@@ -13,7 +13,7 @@
// Contributors:
// 02/01/2022: Tomas Kraus
// - Issue 1442: Implement New JPA API 3.1.0 Features
-package org.eclipse.persistence.jpa.test.criteria.model;
+package org.eclipse.persistence.jpa.test.criteria;
import java.time.Duration;
import java.time.LocalDate;
@@ -29,6 +29,7 @@
import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.criteria.Root;
+import org.eclipse.persistence.jpa.test.criteria.model.DateTimeEntity;
import org.eclipse.persistence.jpa.test.framework.DDLGen;
import org.eclipse.persistence.jpa.test.framework.Emf;
import org.eclipse.persistence.jpa.test.framework.EmfRunner;
@@ -227,9 +228,6 @@
cq.where(cb.and(cb.lessThan(entity.get("time"), cb.localTime()), cb.equal(entity.get("id"), 4)));
em.createQuery(cq).getSingleResult();
em.getTransaction().commit();
- } catch (Throwable t) {
- t.printStackTrace();
- throw t;
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
@@ -255,9 +253,6 @@
List<DateTimeEntity> data = em.createQuery(cq).getResultList();
em.getTransaction().commit();
MatcherAssert.assertThat(data.size(), Matchers.equalTo(0));
- } catch (Throwable t) {
- t.printStackTrace();
- throw t;
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
@@ -281,9 +276,6 @@
cq.where(cb.and(cb.lessThan(entity.get("date"), cb.localDate()), cb.equal(entity.get("id"), 4)));
em.createQuery(cq).getSingleResult();
em.getTransaction().commit();
- } catch (Throwable t) {
- t.printStackTrace();
- throw t;
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
@@ -309,9 +301,6 @@
List<DateTimeEntity> data = em.createQuery(cq).getResultList();
em.getTransaction().commit();
MatcherAssert.assertThat(data.size(), Matchers.equalTo(0));
- } catch (Throwable t) {
- t.printStackTrace();
- throw t;
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
@@ -335,9 +324,6 @@
cq.where(cb.and(cb.lessThan(entity.get("datetime"), cb.localDateTime()), cb.equal(entity.get("id"), 4)));
em.createQuery(cq).getSingleResult();
em.getTransaction().commit();
- } catch (Throwable t) {
- t.printStackTrace();
- throw t;
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
@@ -363,9 +349,6 @@
List<DateTimeEntity> data = em.createQuery(cq).getResultList();
em.getTransaction().commit();
MatcherAssert.assertThat(data.size(), Matchers.equalTo(0));
- } catch (Throwable t) {
- t.printStackTrace();
- throw t;
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
@@ -395,9 +378,6 @@
} else {
MatcherAssert.assertThat(86400000L + diffMilis, Matchers.lessThan(30000L));
}
- } catch (Throwable t) {
- t.printStackTrace();
- throw t;
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
@@ -423,9 +403,6 @@
MatcherAssert.assertThat(diff.getYears(), Matchers.equalTo(0));
MatcherAssert.assertThat(diff.getMonths(), Matchers.equalTo(0));
MatcherAssert.assertThat(diff.getDays(), Matchers.lessThan(2));
- } catch (Throwable t) {
- t.printStackTrace();
- throw t;
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
@@ -449,9 +426,6 @@
em.getTransaction().commit();
long diffMilis = Duration.between(datetime, LocalDateTime.now()).toMillis();
MatcherAssert.assertThat(diffMilis, Matchers.lessThan(30000L));
- } catch (Throwable t) {
- t.printStackTrace();
- throw t;
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/query/TestDateTimeFunctions.java b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/query/TestDateTimeFunctions.java
new file mode 100644
index 0000000..6c481b0
--- /dev/null
+++ b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/query/TestDateTimeFunctions.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+// Contributors:
+// 03/09/2022: Tomas Kraus
+// - Issue 1442: Implement New JPA API 3.1.0 Features
+package org.eclipse.persistence.jpa.test.query;
+
+import java.time.LocalDateTime;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.TypedQuery;
+
+import org.eclipse.persistence.jpa.test.framework.DDLGen;
+import org.eclipse.persistence.jpa.test.framework.Emf;
+import org.eclipse.persistence.jpa.test.framework.EmfRunner;
+import org.eclipse.persistence.jpa.test.framework.Property;
+import org.eclipse.persistence.jpa.test.query.model.DateTimeQueryEntity;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@code LocalTime}/{@code LocalDate}/{@code LocalDateTime} functions in queries.
+ * Added to JPA-API as PR #352
+ */
+@RunWith(EmfRunner.class)
+public class TestDateTimeFunctions {
+ @Emf(createTables = DDLGen.DROP_CREATE,
+ classes = {
+ DateTimeQueryEntity.class
+ },
+ properties = {
+ @Property(name = "eclipselink.cache.shared.default", value = "false"),
+ // This property remaps String from VARCHAR->NVARCHAR(or db equivalent)
+ @Property(name = "eclipselink.target-database-properties",
+ value = "UseNationalCharacterVaryingTypeForString=true"),
+ })
+ private EntityManagerFactory emf;
+
+ private final LocalDateTime[] TS = {
+ LocalDateTime.of(2022, 3, 9, 14, 30, 25, 0)
+ };
+
+ private final DateTimeQueryEntity[] ENTITY = {
+ new DateTimeQueryEntity(1, TS[0].toLocalTime(), TS[0].toLocalDate(), TS[0])
+ };
+
+ @Before
+ public void setup() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ for (DateTimeQueryEntity e : ENTITY) {
+ em.persist(e);
+ }
+ em.flush();
+ em.getTransaction().commit();
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ @After
+ public void cleanup() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ em.createQuery("DELETE FROM DateTimeQueryEntity e").executeUpdate();
+ em.flush();
+ em.getTransaction().commit();
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ // Test JPQL EXTRACT(YEAR FROM date)
+ @Test
+ public void testCriteriaExtractYearFromDate() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(YEAR FROM e.date) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(2022L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ // Test JPQL EXTRACT(QUARTER FROM date)
+ @Test
+ public void testCriteriaExtractQuarterFromDate() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(QUARTER FROM e.date) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(1L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ // Test JPQL EXTRACT(MONTH FROM date)
+ @Test
+ public void testCriteriaExtractMonthFromDate() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(MONTH FROM e.date) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(3L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ // Test JPQL EXTRACT(DAY FROM date)
+ @Test
+ public void testCriteriaExtractDayFromDate() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(DAY FROM e.date) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(9L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ // Test JPQL EXTRACT(HOUR FROM time)
+ @Test
+ public void testCriteriaExtractHourFromTime() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(HOUR FROM e.time) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(14L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ // Test JPQL EXTRACT(MINUTE FROM time)
+ @Test
+ public void testCriteriaExtractMinuteFromTime() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(MINUTE FROM e.time) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(30L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ // Test JPQL EXTRACT(SECOND FROM time)
+ @Test
+ public void testCriteriaExtractSecondFromTime() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(SECOND FROM e.time) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(25L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ /////////////////////////////////////////////////////////
+
+ // Test JPQL EXTRACT(YEAR FROM datetime)
+ @Test
+ public void testCriteriaExtractYearFromDateTime() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(YEAR FROM e.datetime) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(2022L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ // Test JPQL EXTRACT(QUARTER FROM datetime)
+ @Test
+ public void testCriteriaExtractQuarterFromDateTime() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(QUARTER FROM e.datetime) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(1L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ // Test JPQL EXTRACT(MONTH FROM datetime)
+ @Test
+ public void testCriteriaExtractMonthFromDateTime() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(MONTH FROM e.datetime) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(3L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ // Test JPQL EXTRACT(DAY FROM datetime)
+ @Test
+ public void testCriteriaExtractDayFromDateTime() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(DAY FROM e.datetime) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(9L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ // Test JPQL EXTRACT(HOUR FROM datetime)
+ @Test
+ public void testCriteriaExtractHourFromDateTime() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(HOUR FROM e.datetime) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(14L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ // Test JPQL EXTRACT(MINUTE FROM datetime)
+ @Test
+ public void testCriteriaExtractMinuteFromDateTime() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(MINUTE FROM e.datetime) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(30L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+ // Test JPQL EXTRACT(SECOND FROM datetime)
+ @Test
+ public void testCriteriaExtractSecondFromDateTime() {
+ final EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ TypedQuery<Number> q = em.createQuery("SELECT EXTRACT(SECOND FROM e.datetime) FROM DateTimeQueryEntity e WHERE e.id = :id", Number.class);
+ q.setParameter("id", 1);
+ long y = q.getSingleResult().longValue();
+ MatcherAssert.assertThat(y, Matchers.equalTo(25L));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw t;
+ } finally {
+ if (em.getTransaction().isActive()) {
+ em.getTransaction().rollback();
+ }
+ em.close();
+ }
+ }
+
+}
diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/query/model/DateTimeQueryEntity.java b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/query/model/DateTimeQueryEntity.java
new file mode 100644
index 0000000..d754cac
--- /dev/null
+++ b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/query/model/DateTimeQueryEntity.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+// Contributors:
+// 03/09/2022: Tomas Kraus
+// - Issue 1442: Implement New JPA API 3.1.0 Features
+package org.eclipse.persistence.jpa.test.query.model;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+
+/**
+ * JPA Entity used in {@code LocalTime}/{@code LocalDate}/{@code LocalDateTime} tests.
+ */
+@Entity
+public class DateTimeQueryEntity {
+
+ @Id
+ private Integer id;
+
+ private LocalTime time;
+
+ private LocalDate date;
+
+ private LocalDateTime datetime;
+
+ public DateTimeQueryEntity() {
+ }
+
+ public DateTimeQueryEntity(final Integer id, final LocalTime time, final LocalDate date, final LocalDateTime datetime) {
+ this.setId(id);
+ this.setTime(time);
+ this.setDate(date);
+ this.setDatetime(datetime);
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public LocalTime getTime() {
+ return time;
+ }
+
+ public void setTime(LocalTime time) {
+ this.time = time;
+ }
+
+ public LocalDate getDate() {
+ return date;
+ }
+
+ public void setDate(LocalDate date) {
+ this.date = date;
+ }
+
+ public LocalDateTime getDatetime() {
+ return datetime;
+ }
+
+ public void setDatetime(LocalDateTime datetime) {
+ this.datetime = datetime;
+ }
+
+}