Skip to content

Commit

Permalink
Changed second fraction precision of LocalDateTime and OffsetDateTime…
Browse files Browse the repository at this point in the history
… MySQL related type. (#1456)

Signed-off-by: Tomas Kraus <tomas.kraus@oracle.com>
  • Loading branch information
Tomas-Kraus committed Mar 21, 2022
1 parent accd3d7 commit 9f98c8b
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ protected Hashtable<Class<?>, FieldTypeDefinition> buildFieldTypes() {
if (!isFractionalTimeSupported) {
fd.setIsSizeAllowed(false);
} else {
fd.setDefaultSize(3);
fd.setDefaultSize(6);
fd.setIsSizeRequired(true);
}
fieldTypeMapping.put(java.time.LocalDateTime.class,fd); //no timezone info
Expand All @@ -224,7 +224,7 @@ protected Hashtable<Class<?>, FieldTypeDefinition> buildFieldTypes() {
if (!isFractionalTimeSupported) {
fd.setIsSizeAllowed(false);
} else {
fd.setDefaultSize(3);
fd.setDefaultSize(6);
fd.setIsSizeRequired(true);
}
fieldTypeMapping.put(java.time.LocalTime.class, fd);
Expand All @@ -233,7 +233,7 @@ protected Hashtable<Class<?>, FieldTypeDefinition> buildFieldTypes() {
if (!isFractionalTimeSupported) {
fd.setIsSizeAllowed(false);
} else {
fd.setDefaultSize(3);
fd.setDefaultSize(6);
fd.setIsSizeRequired(true);
}
fieldTypeMapping.put(java.time.OffsetDateTime.class, fd); //no timezone info
Expand All @@ -242,7 +242,7 @@ protected Hashtable<Class<?>, FieldTypeDefinition> buildFieldTypes() {
if (!isFractionalTimeSupported) {
fd.setIsSizeAllowed(false);
} else {
fd.setDefaultSize(3);
fd.setDefaultSize(6);
fd.setIsSizeRequired(true);
}
fieldTypeMapping.put(java.time.OffsetTime.class, fd);
Expand Down Expand Up @@ -384,6 +384,11 @@ public boolean isMySQL() {
@Override
protected void initializePlatformOperators() {
super.initializePlatformOperators();
addOperator(currentTimeStamp());
addOperator(today());
addOperator(currentTime());
addOperator(localTime());
addOperator(localDateTime());
addOperator(logOperator());
addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Atan2, "ATAN2"));
addOperator(ExpressionOperator.simpleTwoArgumentFunction(ExpressionOperator.Concat, "CONCAT"));
Expand All @@ -397,6 +402,60 @@ protected void initializePlatformOperators() {
addOperator(rightTrim2());
}

/**
* INTERNAL:
* MySQL specific {@code currentTimeStamp} operator.
*
* @return new {@link ExpressionOperator} instance with {@code currentTimeStamp}
*/
public static ExpressionOperator currentTimeStamp() {
return ExpressionOperator.simpleFunctionNoParentheses(
ExpressionOperator.Today, "CURRENT_TIMESTAMP(6)");
}

/**
* INTERNAL:
* MySQL specific {@code today} operator.
*
* @return new {@link ExpressionOperator} instance with {@code today}
*/
public static ExpressionOperator today() {
return currentTimeStamp();
}

/**
* INTERNAL:
* MySQL specific {@code currentTime} operator.
*
* @return new {@link ExpressionOperator} instance with {@code currentTime}
*/
public static ExpressionOperator currentTime() {
return ExpressionOperator.simpleFunctionNoParentheses(
ExpressionOperator.CurrentTime, "CURRENT_TIME(6)");
}

/**
* INTERNAL:
* MySQL specific {@code localTime} operator.
*
* @return new {@link ExpressionOperator} instance with {@code localTime}
*/
public static ExpressionOperator localTime() {
return ExpressionOperator.simpleFunctionNoParentheses(
ExpressionOperator.LocalTime, "CURRENT_TIME(6)");
}

/**
* INTERNAL:
* MySQL specific {@code localDateTime} operator.
*
* @return new {@link ExpressionOperator} instance with {@code localDateTime}
*/
public static ExpressionOperator localDateTime() {
return ExpressionOperator.simpleFunctionNoParentheses(
ExpressionOperator.LocalDateTime, "CURRENT_TIMESTAMP(6)");
}

/**
* INTERNAL:
* Create the 10 based log operator for this platform.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.time.temporal.ChronoUnit;
import java.util.List;

import jakarta.persistence.EntityManager;
Expand All @@ -34,6 +35,8 @@
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.logging.AbstractSessionLog;
import org.eclipse.persistence.logging.SessionLog;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.After;
Expand Down Expand Up @@ -80,6 +83,33 @@ public class TestDateTimeFunctions {
// testCriteriaQuerySelectLocalDateTime
};

// Database vs. Java timezone offset in seconds. Must be applied to LocalDateTime calculations.
private long dbOffset = 0;

// Update database vs. Java timezone offset using current database time.
private void updateDbOffset() {
final EntityManager em = emf.createEntityManager();
try {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<LocalTime> cq = cb.createQuery(LocalTime.class);
cq.select(cb.localTime());
Root<DateTimeEntity> entity = cq.from(DateTimeEntity.class);
cq.where(cb.equal(entity.get("id"), 1));
LocalTime dbTime = em.createQuery(cq).getSingleResult();
LocalTime javaTime = LocalTime.now();
this.dbOffset = dbTime.truncatedTo(ChronoUnit.SECONDS).toSecondOfDay() - javaTime.truncatedTo(ChronoUnit.SECONDS).toSecondOfDay();
} catch (Throwable t) {
AbstractSessionLog.getLog().log(SessionLog.WARNING, "Can't update DB offset: " + t.getMessage());
t.printStackTrace();
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
em.close();
}

}

@Before
public void setup() {
final EntityManager em = emf.createEntityManager();
Expand All @@ -96,6 +126,7 @@ public void setup() {
}
em.close();
}
updateDbOffset();
}

@After
Expand Down Expand Up @@ -134,7 +165,7 @@ public void testCriteriaUpdateLocalTime() {
em.getTransaction().commit();
// Verify updated entity
DateTimeEntity data = em.find(DateTimeEntity.class, 1);
long diffMilis = Duration.between(data.getTime(), LocalTime.now()).toMillis();
long diffMilis = Duration.between(data.getTime(), LocalTime.now().plusSeconds(dbOffset + 1)).toMillis();
// Positive value means that test did not pass midnight.
if (diffMilis > 0) {
MatcherAssert.assertThat(diffMilis, Matchers.lessThan(30000L));
Expand Down Expand Up @@ -203,7 +234,7 @@ public void testCriteriaUpdateLocalDateTime() {
em.getTransaction().commit();
// Verify updated entity
DateTimeEntity data = em.find(DateTimeEntity.class, 3);
long diffMilis = Duration.between(data.getDatetime(), LocalDateTime.now()).toMillis();
long diffMilis = Duration.between(data.getDatetime(), LocalDateTime.now().plusSeconds(dbOffset + 1)).toMillis();
MatcherAssert.assertThat(diffMilis, Matchers.lessThan(30000L));
} finally {
if (em.getTransaction().isActive()) {
Expand Down Expand Up @@ -370,7 +401,7 @@ public void testCriteriaQuerySelectLocalTime() {
cq.where(cb.equal(entity.get("id"), 4));
LocalTime time = em.createQuery(cq).getSingleResult();
em.getTransaction().commit();
long diffMilis = Duration.between(time, LocalTime.now()).toMillis();
long diffMilis = Duration.between(time, LocalTime.now().plusSeconds(1 + dbOffset)).toMillis();
// Positive value means that test did not pass midnight.
if (diffMilis > 0) {
MatcherAssert.assertThat(diffMilis, Matchers.lessThan(30000L));
Expand Down Expand Up @@ -424,7 +455,7 @@ public void testCriteriaQuerySelectLocalDateTime() {
cq.where(cb.equal(entity.get("id"), 4));
LocalDateTime datetime = em.createQuery(cq).getSingleResult();
em.getTransaction().commit();
long diffMilis = Duration.between(datetime, LocalDateTime.now()).toMillis();
long diffMilis = Duration.between(datetime, LocalDateTime.now().plusSeconds(dbOffset + 1)).toMillis();
MatcherAssert.assertThat(diffMilis, Matchers.lessThan(30000L));
} finally {
if (em.getTransaction().isActive()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.eclipse.persistence.jpa.test.query;

import java.time.LocalDateTime;
import java.util.List;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
Expand Down Expand Up @@ -52,11 +53,13 @@ public class TestDateTimeFunctions {
private EntityManagerFactory emf;

private final LocalDateTime[] TS = {
LocalDateTime.of(2022, 3, 9, 14, 30, 25, 0)
LocalDateTime.of(2022, 3, 9, 14, 30, 25, 0),
LocalDateTime.now()
};

private final DateTimeQueryEntity[] ENTITY = {
new DateTimeQueryEntity(1, TS[0].toLocalTime(), TS[0].toLocalDate(), TS[0])
new DateTimeQueryEntity(1, TS[0].toLocalTime(), TS[0].toLocalDate(), TS[0]),
new DateTimeQueryEntity(2, TS[1].toLocalTime(), TS[1].toLocalDate(), TS[1])
};

@Before
Expand Down Expand Up @@ -389,4 +392,26 @@ public void testCriteriaExtractSecondFromDateTime() {
}
}

// Test LocalDateTime.now() in WHERE clause
// SELECT e FROM DateTimeQueryEntity e WHERE e.datetime = :dateTime
@Test
public void testLocalDateTime() {
final EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
TypedQuery<DateTimeQueryEntity> query = em.createNamedQuery("DateTimeQueryEntity.findByLocalDateTime", DateTimeQueryEntity.class);
query.setParameter("dateTime", TS[1]);
List<DateTimeQueryEntity> result = query.getResultList();
MatcherAssert.assertThat(result.size(), Matchers.equalTo(1));
} catch (Throwable t) {
t.printStackTrace();
throw t;
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
em.close();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.NamedQuery;

/**
* JPA Entity used in {@code LocalTime}/{@code LocalDate}/{@code LocalDateTime} tests.
*/
@Entity
@NamedQuery(name = "DateTimeQueryEntity.findByLocalDateTime", query = "SELECT e FROM DateTimeQueryEntity e WHERE e.datetime = :dateTime")
public class DateTimeQueryEntity {

@Id
Expand Down

0 comments on commit 9f98c8b

Please sign in to comment.