diff --git a/src/main/java/org/apache/ibatis/type/JdbcType.java b/src/main/java/org/apache/ibatis/type/JdbcType.java index 94d4ed55b08..c0fcc3256f1 100644 --- a/src/main/java/org/apache/ibatis/type/JdbcType.java +++ b/src/main/java/org/apache/ibatis/type/JdbcType.java @@ -65,7 +65,9 @@ public enum JdbcType { ROWID(Types.ROWID), // JDK6 LONGNVARCHAR(Types.LONGNVARCHAR), // JDK6 SQLXML(Types.SQLXML), // JDK6 - DATETIMEOFFSET(-155); // SQL Server 2008 + DATETIMEOFFSET(-155), // SQL Server 2008 + TIME_WITH_TIMEZONE(Types.TIME_WITH_TIMEZONE), // JDBC 4.2 JDK8 + TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE); // JDBC 4.2 JDK8 public final int TYPE_CODE; private static Map codeLookup = new HashMap<>(); diff --git a/src/main/java/org/apache/ibatis/type/OffsetDateTimeTypeHandler.java b/src/main/java/org/apache/ibatis/type/OffsetDateTimeTypeHandler.java index a82b041da2b..3c7b8877745 100644 --- a/src/main/java/org/apache/ibatis/type/OffsetDateTimeTypeHandler.java +++ b/src/main/java/org/apache/ibatis/type/OffsetDateTimeTypeHandler.java @@ -19,9 +19,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Timestamp; import java.time.OffsetDateTime; -import java.time.ZoneId; /** * @since 3.4.5 @@ -32,31 +30,22 @@ public class OffsetDateTimeTypeHandler extends BaseTypeHandler { @Override public void setNonNullParameter(PreparedStatement ps, int i, OffsetDateTime parameter, JdbcType jdbcType) throws SQLException { - ps.setTimestamp(i, Timestamp.from(parameter.toInstant())); + ps.setObject(i, parameter); } @Override public OffsetDateTime getNullableResult(ResultSet rs, String columnName) throws SQLException { - Timestamp timestamp = rs.getTimestamp(columnName); - return getOffsetDateTime(timestamp); + return rs.getObject(columnName, OffsetDateTime.class); } @Override public OffsetDateTime getNullableResult(ResultSet rs, int columnIndex) throws SQLException { - Timestamp timestamp = rs.getTimestamp(columnIndex); - return getOffsetDateTime(timestamp); + return rs.getObject(columnIndex, OffsetDateTime.class); } @Override public OffsetDateTime getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { - Timestamp timestamp = cs.getTimestamp(columnIndex); - return getOffsetDateTime(timestamp); + return cs.getObject(columnIndex, OffsetDateTime.class); } - private static OffsetDateTime getOffsetDateTime(Timestamp timestamp) { - if (timestamp != null) { - return OffsetDateTime.ofInstant(timestamp.toInstant(), ZoneId.systemDefault()); - } - return null; - } } diff --git a/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/CreateDB.sql b/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/CreateDB.sql new file mode 100644 index 00000000000..6a47889b02a --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/CreateDB.sql @@ -0,0 +1,25 @@ +-- +-- Copyright 2009-2017 the original author or authors. +-- +-- Licensed 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. +-- + +drop table records if exists; + +create table records ( + id int, + odt timestamp with time zone +); + +insert into records (id, odt) values +(1, '2018-01-02 11:22:33.123456000+01:23'); diff --git a/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/Mapper.java b/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/Mapper.java new file mode 100644 index 00000000000..775f9112c9d --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/Mapper.java @@ -0,0 +1,29 @@ +/** + * Copyright 2009-2017 the original author or authors. + * + * Licensed 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.ibatis.submitted.timestamp_with_timezone; + +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Select; + +public interface Mapper { + + @Select("select id, odt from records where id = #{id}") + Record selectById(Integer id); + + @Insert("insert into records (id, odt) values (#{id}, #{odt})") + int insertOffsetDateTime(Record record); + +} diff --git a/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/Record.java b/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/Record.java new file mode 100644 index 00000000000..5f371cd1468 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/Record.java @@ -0,0 +1,42 @@ +/** + * Copyright 2009-2017 the original author or authors. + * + * Licensed 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.ibatis.submitted.timestamp_with_timezone; + +import java.time.OffsetDateTime; + +public class Record { + + private Integer id; + + private OffsetDateTime odt; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public OffsetDateTime getOdt() { + return odt; + } + + public void setOdt(OffsetDateTime odt) { + this.odt = odt; + } + +} diff --git a/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/TimestampWithTimezoneTypeHandlerTest.java b/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/TimestampWithTimezoneTypeHandlerTest.java new file mode 100644 index 00000000000..03ebde41084 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/TimestampWithTimezoneTypeHandlerTest.java @@ -0,0 +1,75 @@ +/** + * Copyright 2009-2017 the original author or authors. + * + * Licensed 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.ibatis.submitted.timestamp_with_timezone; + +import static org.junit.jupiter.api.Assertions.*; + +import java.io.Reader; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import org.apache.ibatis.BaseDataTest; +import org.apache.ibatis.io.Resources; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class TimestampWithTimezoneTypeHandlerTest { + + private static SqlSessionFactory sqlSessionFactory; + + @BeforeAll + public static void setUp() throws Exception { + try (Reader reader = Resources + .getResourceAsReader("org/apache/ibatis/submitted/timestamp_with_timezone/mybatis-config.xml")) { + sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); + } + BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), + "org/apache/ibatis/submitted/timestamp_with_timezone/CreateDB.sql"); + } + + @Test + public void shouldSelectOffsetDateTime() { + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + Mapper mapper = sqlSession.getMapper(Mapper.class); + Record record = mapper.selectById(1); + assertEquals(OffsetDateTime.of(2018, 1, 2, 11, 22, 33, 123456000, ZoneOffset.ofHoursMinutes(1, 23)), + record.getOdt()); + } + } + + @Test + public void shouldInsertOffsetDateTime() { + OffsetDateTime odt = OffsetDateTime.of(2018, 1, 2, 11, 22, 33, 123456000, ZoneOffset.ofHoursMinutes(1, 23)); + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + Mapper mapper = sqlSession.getMapper(Mapper.class); + Record record = new Record(); + record.setId(2); + record.setOdt(odt); + int result = mapper.insertOffsetDateTime(record); + assertEquals(1, result); + sqlSession.commit(); + } + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + Mapper mapper = sqlSession.getMapper(Mapper.class); + Record record = mapper.selectById(2); + assertEquals(odt, record.getOdt()); + } + } + +} diff --git a/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/mybatis-config.xml b/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/mybatis-config.xml new file mode 100644 index 00000000000..d70c6fb2eb0 --- /dev/null +++ b/src/test/java/org/apache/ibatis/submitted/timestamp_with_timezone/mybatis-config.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/org/apache/ibatis/type/OffsetDateTimeTypeHandlerTest.java b/src/test/java/org/apache/ibatis/type/OffsetDateTimeTypeHandlerTest.java index d8f0c6530c0..4e1d6c777d7 100644 --- a/src/test/java/org/apache/ibatis/type/OffsetDateTimeTypeHandlerTest.java +++ b/src/test/java/org/apache/ibatis/type/OffsetDateTimeTypeHandlerTest.java @@ -18,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; -import java.sql.Timestamp; import java.time.OffsetDateTime; import org.junit.jupiter.api.Test; @@ -27,19 +26,18 @@ public class OffsetDateTimeTypeHandlerTest extends BaseTypeHandlerTest { private static final TypeHandler TYPE_HANDLER = new OffsetDateTimeTypeHandler(); private static final OffsetDateTime OFFSET_DATE_TIME = OffsetDateTime.now(); - private static final Timestamp TIMESTAMP = Timestamp.from(OFFSET_DATE_TIME.toInstant()); @Override @Test public void shouldSetParameter() throws Exception { TYPE_HANDLER.setParameter(ps, 1, OFFSET_DATE_TIME, null); - verify(ps).setTimestamp(1, TIMESTAMP); + verify(ps).setObject(1, OFFSET_DATE_TIME); } @Override @Test public void shouldGetResultFromResultSetByName() throws Exception { - when(rs.getTimestamp("column")).thenReturn(TIMESTAMP); + when(rs.getObject("column", OffsetDateTime.class)).thenReturn(OFFSET_DATE_TIME); assertEquals(OFFSET_DATE_TIME, TYPE_HANDLER.getResult(rs, "column")); verify(rs, never()).wasNull(); } @@ -47,7 +45,7 @@ public void shouldGetResultFromResultSetByName() throws Exception { @Override @Test public void shouldGetResultNullFromResultSetByName() throws Exception { - when(rs.getTimestamp("column")).thenReturn(null); + when(rs.getObject("column", OffsetDateTime.class)).thenReturn(null); assertNull(TYPE_HANDLER.getResult(rs, "column")); verify(rs, never()).wasNull(); } @@ -55,7 +53,7 @@ public void shouldGetResultNullFromResultSetByName() throws Exception { @Override @Test public void shouldGetResultFromResultSetByPosition() throws Exception { - when(rs.getTimestamp(1)).thenReturn(TIMESTAMP); + when(rs.getObject(1, OffsetDateTime.class)).thenReturn(OFFSET_DATE_TIME); assertEquals(OFFSET_DATE_TIME, TYPE_HANDLER.getResult(rs, 1)); verify(rs, never()).wasNull(); } @@ -63,7 +61,7 @@ public void shouldGetResultFromResultSetByPosition() throws Exception { @Override @Test public void shouldGetResultNullFromResultSetByPosition() throws Exception { - when(rs.getTimestamp(1)).thenReturn(null); + when(rs.getObject(1, OffsetDateTime.class)).thenReturn(null); assertNull(TYPE_HANDLER.getResult(rs, 1)); verify(rs, never()).wasNull(); } @@ -71,7 +69,7 @@ public void shouldGetResultNullFromResultSetByPosition() throws Exception { @Override @Test public void shouldGetResultFromCallableStatement() throws Exception { - when(cs.getTimestamp(1)).thenReturn(TIMESTAMP); + when(cs.getObject(1, OffsetDateTime.class)).thenReturn(OFFSET_DATE_TIME); assertEquals(OFFSET_DATE_TIME, TYPE_HANDLER.getResult(cs, 1)); verify(cs, never()).wasNull(); } @@ -79,8 +77,9 @@ public void shouldGetResultFromCallableStatement() throws Exception { @Override @Test public void shouldGetResultNullFromCallableStatement() throws Exception { - when(cs.getTimestamp(1)).thenReturn(null); + when(cs.getObject(1, OffsetDateTime.class)).thenReturn(null); assertNull(TYPE_HANDLER.getResult(cs, 1)); verify(cs, never()).wasNull(); } + }