You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2020/11/18 09:14:49 UTC
[cayenne] 01/02: CAY-2691 MySQL driver 8.0.x stores LocalDateTime
differently than 5.1.x
This is an automated email from the ASF dual-hosted git repository.
ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git
commit 3b64f0c1b2583ab505f32e1a14569a199e00b566
Author: Nikita Timofeev <st...@gmail.com>
AuthorDate: Wed Nov 18 12:14:16 2020 +0300
CAY-2691 MySQL driver 8.0.x stores LocalDateTime differently than 5.1.x
---
.../org/apache/cayenne/access/types/DateType.java | 29 ++++++-
.../org/apache/cayenne/access/types/TimeType.java | 29 ++++++-
.../apache/cayenne/access/types/TimestampType.java | 29 ++++++-
.../apache/cayenne/access/types/UtilDateType.java | 97 ++++++++++++++++------
.../org/apache/cayenne/dba/mysql/MySQLAdapter.java | 10 +++
.../org/apache/cayenne/access/DateTimeTypesIT.java | 28 +++----
6 files changed, 178 insertions(+), 44 deletions(-)
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/types/DateType.java b/cayenne-server/src/main/java/org/apache/cayenne/access/types/DateType.java
index 5521ada..0c5ba3d 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/types/DateType.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/types/DateType.java
@@ -22,12 +22,35 @@ import java.sql.CallableStatement;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
+import java.util.Calendar;
/**
* @since 3.0
*/
public class DateType implements ExtendedType<Date> {
+ private final Calendar calendar;
+ private final boolean useCalendar;
+
+ /**
+ * @since 4.2
+ */
+ public DateType() {
+ this(false);
+ }
+
+ /**
+ * @since 4.2
+ */
+ public DateType(boolean useCalendar) {
+ this.useCalendar = useCalendar;
+ if(this.useCalendar) {
+ this.calendar = Calendar.getInstance();
+ } else {
+ this.calendar = null;
+ }
+ }
+
@Override
public String getClassName() {
return Date.class.getName();
@@ -35,12 +58,12 @@ public class DateType implements ExtendedType<Date> {
@Override
public Date materializeObject(ResultSet rs, int index, int type) throws Exception {
- return rs.getDate(index);
+ return useCalendar ? rs.getDate(index, calendar) : rs.getDate(index);
}
@Override
public Date materializeObject(CallableStatement rs, int index, int type) throws Exception {
- return rs.getDate(index);
+ return useCalendar ? rs.getDate(index, calendar) : rs.getDate(index);
}
@Override
@@ -53,6 +76,8 @@ public class DateType implements ExtendedType<Date> {
if (value == null) {
statement.setNull(pos, type);
+ } else if(useCalendar) {
+ statement.setDate(pos, value, calendar);
} else {
statement.setDate(pos, value);
}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/types/TimeType.java b/cayenne-server/src/main/java/org/apache/cayenne/access/types/TimeType.java
index 46821bd..d0db8c8 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/types/TimeType.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/types/TimeType.java
@@ -22,12 +22,35 @@ import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Time;
+import java.util.Calendar;
/**
* @since 3.0
*/
public class TimeType implements ExtendedType<Time> {
+ private final Calendar calendar;
+ private final boolean useCalendar;
+
+ /**
+ * @since 4.2
+ */
+ public TimeType() {
+ this(false);
+ }
+
+ /**
+ * @since 4.2
+ */
+ public TimeType(boolean useCalendar) {
+ this.useCalendar = useCalendar;
+ if(this.useCalendar) {
+ this.calendar = Calendar.getInstance();
+ } else {
+ this.calendar = null;
+ }
+ }
+
@Override
public String getClassName() {
return Time.class.getName();
@@ -35,12 +58,12 @@ public class TimeType implements ExtendedType<Time> {
@Override
public Time materializeObject(ResultSet rs, int index, int type) throws Exception {
- return rs.getTime(index);
+ return useCalendar ? rs.getTime(index, calendar) : rs.getTime(index);
}
@Override
public Time materializeObject(CallableStatement rs, int index, int type) throws Exception {
- return rs.getTime(index);
+ return useCalendar ? rs.getTime(index, calendar) : rs.getTime(index);
}
@Override
@@ -53,6 +76,8 @@ public class TimeType implements ExtendedType<Time> {
if (value == null) {
statement.setNull(pos, type);
+ } else if(useCalendar) {
+ statement.setTime(pos, value, calendar);
} else {
statement.setTime(pos, value);
}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/types/TimestampType.java b/cayenne-server/src/main/java/org/apache/cayenne/access/types/TimestampType.java
index cecf325..a89772d 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/types/TimestampType.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/types/TimestampType.java
@@ -22,12 +22,35 @@ import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
+import java.util.Calendar;
/**
* @since 3.0
*/
public class TimestampType implements ExtendedType<Timestamp> {
+ private final Calendar calendar;
+ private final boolean useCalendar;
+
+ /**
+ * @since 4.2
+ */
+ public TimestampType() {
+ this(false);
+ }
+
+ /**
+ * @since 4.2
+ */
+ public TimestampType(boolean useCalendar) {
+ this.useCalendar = useCalendar;
+ if(this.useCalendar) {
+ this.calendar = Calendar.getInstance();
+ } else {
+ this.calendar = null;
+ }
+ }
+
@Override
public String getClassName() {
return Timestamp.class.getName();
@@ -35,12 +58,12 @@ public class TimestampType implements ExtendedType<Timestamp> {
@Override
public Timestamp materializeObject(ResultSet rs, int index, int type) throws Exception {
- return rs.getTimestamp(index);
+ return useCalendar ? rs.getTimestamp(index, calendar) : rs.getTimestamp(index);
}
@Override
public Timestamp materializeObject(CallableStatement cs, int index, int type) throws Exception {
- return cs.getTimestamp(index);
+ return useCalendar ? cs.getTimestamp(index, calendar) : cs.getTimestamp(index);
}
@Override
@@ -53,6 +76,8 @@ public class TimestampType implements ExtendedType<Timestamp> {
if (value == null) {
statement.setNull(pos, type);
+ } else if(useCalendar) {
+ statement.setTimestamp(pos, value, calendar);
} else {
statement.setTimestamp(pos, value);
}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/types/UtilDateType.java b/cayenne-server/src/main/java/org/apache/cayenne/access/types/UtilDateType.java
index b87a72e..2e9d7b0 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/types/UtilDateType.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/types/UtilDateType.java
@@ -24,7 +24,9 @@ import org.apache.cayenne.dba.TypesMapping;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
+import java.sql.Time;
import java.sql.Types;
+import java.util.Calendar;
import java.util.Date;
/**
@@ -33,43 +35,59 @@ import java.util.Date;
*/
public class UtilDateType implements ExtendedType<Date> {
+ private final Calendar calendar;
+ private final boolean useCalendar;
+
/**
- * Returns "java.util.Date".
+ * @since 4.2
*/
- @Override
- public String getClassName() {
- return Date.class.getName();
+ public UtilDateType() {
+ this(false);
}
- protected Object convertToJdbcObject(Date val, int type) throws Exception {
- if (type == Types.DATE) {
- return new java.sql.Date(val.getTime());
- } else if (type == Types.TIME) {
- return new java.sql.Time(val.getTime());
- } else if (type == Types.TIMESTAMP) {
- return new java.sql.Timestamp(val.getTime());
+ /**
+ * @since 4.2
+ */
+ public UtilDateType(boolean useCalendar) {
+ this.useCalendar = useCalendar;
+ if(this.useCalendar) {
+ this.calendar = Calendar.getInstance();
} else {
- throw new IllegalArgumentException(
- "Only DATE, TIME or TIMESTAMP can be mapped as '" + getClassName()
- + "', got " + TypesMapping.getSqlNameByType(type));
+ this.calendar = null;
}
}
+ /**
+ * Returns "java.util.Date".
+ */
+ @Override
+ public String getClassName() {
+ return Date.class.getName();
+ }
+
@Override
public Date materializeObject(ResultSet rs, int index, int type) throws Exception {
Date val;
switch (type) {
case Types.TIMESTAMP:
- val = rs.getTimestamp(index);
+ val = useCalendar
+ ? rs.getTimestamp(index, calendar)
+ : rs.getTimestamp(index);
break;
case Types.DATE:
- val = rs.getDate(index);
+ val = useCalendar
+ ? rs.getDate(index, calendar)
+ : rs.getDate(index);
break;
case Types.TIME:
- val = rs.getTime(index);
+ val = useCalendar
+ ? rs.getTime(index, calendar)
+ : rs.getTime(index);
break;
default:
- val = rs.getTimestamp(index);
+ val = useCalendar
+ ? rs.getTimestamp(index, calendar)
+ : rs.getTimestamp(index);
break;
}
@@ -82,16 +100,24 @@ public class UtilDateType implements ExtendedType<Date> {
Date val;
switch (type) {
case Types.TIMESTAMP:
- val = cs.getTimestamp(index);
+ val = useCalendar
+ ? cs.getTimestamp(index, calendar)
+ : cs.getTimestamp(index);
break;
case Types.DATE:
- val = cs.getDate(index);
+ val = useCalendar
+ ? cs.getDate(index, calendar)
+ : cs.getDate(index);
break;
case Types.TIME:
- val = cs.getTime(index);
+ val = useCalendar
+ ? cs.getTime(index, calendar)
+ : cs.getTime(index);
break;
default:
- val = cs.getTimestamp(index);
+ val = useCalendar
+ ? cs.getTimestamp(index, calendar)
+ : cs.getTimestamp(index);
break;
}
@@ -110,7 +136,30 @@ public class UtilDateType implements ExtendedType<Date> {
if (value == null) {
statement.setNull(pos, type);
} else {
- statement.setObject(pos, convertToJdbcObject(value, type), type);
+ if (type == Types.DATE) {
+ if(useCalendar) {
+ statement.setDate(pos, new java.sql.Date(value.getTime()), calendar);
+ } else {
+ statement.setDate(pos, new java.sql.Date(value.getTime()));
+ }
+ } else if (type == Types.TIME) {
+ Time time = new Time(value.getTime());
+ if(useCalendar) {
+ statement.setTime(pos, time, calendar);
+ } else {
+ statement.setTime(pos, time);
+ }
+ } else if (type == Types.TIMESTAMP) {
+ if(useCalendar) {
+ statement.setTimestamp(pos, new java.sql.Timestamp(value.getTime()), calendar);
+ } else {
+ statement.setTimestamp(pos, new java.sql.Timestamp(value.getTime()));
+ }
+ } else {
+ throw new IllegalArgumentException(
+ "Only DATE, TIME or TIMESTAMP can be mapped as '" + getClassName()
+ + "', got " + TypesMapping.getSqlNameByType(type));
+ }
}
}
@@ -121,6 +170,6 @@ public class UtilDateType implements ExtendedType<Date> {
}
long time = value.getTime();
- return "\'" + new java.sql.Timestamp(time) + "\'";
+ return '\'' + new java.sql.Timestamp(time).toString() + '\'';
}
}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java
index 1c28171..32044e0 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLAdapter.java
@@ -36,10 +36,14 @@ import org.apache.cayenne.access.translator.ejbql.EJBQLTranslatorFactory;
import org.apache.cayenne.access.translator.ejbql.JdbcEJBQLTranslatorFactory;
import org.apache.cayenne.access.types.ByteArrayType;
import org.apache.cayenne.access.types.CharType;
+import org.apache.cayenne.access.types.DateType;
import org.apache.cayenne.access.types.ExtendedType;
import org.apache.cayenne.access.types.ExtendedTypeFactory;
import org.apache.cayenne.access.types.ExtendedTypeMap;
import org.apache.cayenne.access.types.JsonType;
+import org.apache.cayenne.access.types.TimeType;
+import org.apache.cayenne.access.types.TimestampType;
+import org.apache.cayenne.access.types.UtilDateType;
import org.apache.cayenne.access.types.ValueObjectTypeRegistry;
import org.apache.cayenne.configuration.Constants;
import org.apache.cayenne.configuration.RuntimeProperties;
@@ -153,6 +157,12 @@ public class MySQLAdapter extends JdbcAdapter {
map.registerType(charType);
map.registerType(new ByteArrayType(false, false));
map.registerType(new JsonType(charType, true));
+
+ // register non-default types for the dates, see CAY-2691
+ map.registerType(new DateType(true));
+ map.registerType(new TimeType(true));
+ map.registerType(new TimestampType(true));
+ map.registerType(new UtilDateType(true));
}
@Override
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DateTimeTypesIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DateTimeTypesIT.java
index 2031afa..94b2312 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/DateTimeTypesIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/DateTimeTypesIT.java
@@ -48,13 +48,13 @@ public class DateTimeTypesIT extends ServerCase {
private DataContext context;
@Test
- public void testCalendar() throws Exception {
+ public void testCalendar() {
CalendarEntity test = context.newObject(CalendarEntity.class);
Calendar cal = Calendar.getInstance();
cal.clear();
- cal.set(2002, 1, 1);
+ cal.set(2002, Calendar.FEBRUARY, 1);
test.setCalendarField(cal);
context.commitChanges();
@@ -69,12 +69,12 @@ public class DateTimeTypesIT extends ServerCase {
}
@Test
- public void testDate() throws Exception {
+ public void testDate() {
DateTestEntity test = context.newObject(DateTestEntity.class);
Calendar cal = Calendar.getInstance();
cal.clear();
- cal.set(2002, 1, 1);
+ cal.set(2002, Calendar.FEBRUARY, 1);
Date nowDate = cal.getTime();
test.setDateColumn(nowDate);
context.commitChanges();
@@ -87,12 +87,12 @@ public class DateTimeTypesIT extends ServerCase {
}
@Test
- public void testTime() throws Exception {
+ public void testTime() {
DateTestEntity test = context.newObject(DateTestEntity.class);
Calendar cal = Calendar.getInstance();
cal.clear();
- cal.set(1970, 0, 1, 1, 20, 30);
+ cal.set(1970, Calendar.JANUARY, 1, 1, 20, 30);
Date nowTime = cal.getTime();
test.setTimeColumn(nowTime);
context.commitChanges();
@@ -112,12 +112,12 @@ public class DateTimeTypesIT extends ServerCase {
}
@Test
- public void testTimestamp() throws Exception {
+ public void testTimestamp() {
DateTestEntity test = context.newObject(DateTestEntity.class);
Calendar cal = Calendar.getInstance();
cal.clear();
- cal.set(2003, 1, 1, 1, 20, 30);
+ cal.set(2003, Calendar.FEBRUARY, 1, 1, 20, 30);
// most databases fail millisecond accuracy
// cal.set(Calendar.MILLISECOND, 55);
@@ -133,12 +133,12 @@ public class DateTimeTypesIT extends ServerCase {
}
@Test
- public void testSQLTemplateTimestamp() throws Exception {
+ public void testSQLTemplateTimestamp() {
DateTestEntity test = context.newObject(DateTestEntity.class);
Calendar cal = Calendar.getInstance();
cal.clear();
- cal.set(2003, 1, 1, 1, 20, 30);
+ cal.set(2003, Calendar.FEBRUARY, 1, 1, 20, 30);
// most databases fail millisecond accuracy
// cal.set(Calendar.MILLISECOND, 55);
@@ -154,12 +154,12 @@ public class DateTimeTypesIT extends ServerCase {
}
@Test
- public void testSQLTemplateDate() throws Exception {
+ public void testSQLTemplateDate() {
DateTestEntity test = (DateTestEntity) context.newObject("DateTestEntity");
Calendar cal = Calendar.getInstance();
cal.clear();
- cal.set(2003, 1, 1, 1, 20, 30);
+ cal.set(2003, Calendar.FEBRUARY, 1, 1, 20, 30);
// most databases fail millisecond accuracy
// cal.set(Calendar.MILLISECOND, 55);
@@ -175,12 +175,12 @@ public class DateTimeTypesIT extends ServerCase {
}
@Test
- public void testSQLTemplateTime() throws Exception {
+ public void testSQLTemplateTime() {
DateTestEntity test = (DateTestEntity) context.newObject("DateTestEntity");
Calendar cal = Calendar.getInstance();
cal.clear();
- cal.set(2003, 1, 1, 1, 20, 30);
+ cal.set(2003, Calendar.FEBRUARY, 1, 1, 20, 30);
// most databases fail millisecond accuracy
// cal.set(Calendar.MILLISECOND, 55);