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 <[email protected]> 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);
