Unverified 提交 f9dda484 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1359 from katzyn/OffsetDateTime

Add system property to return OffsetDateTime from ResultSet.getObject()
......@@ -71,6 +71,16 @@ public class SysProperties {
public static final String USER_HOME =
Utils.getProperty("user.home", "");
/**
* System property {@code h2.preview} (default: false).
* <p>
* Controls default values of other properties. If {@code true} default
* values of other properties are changed to planned defaults for the 1.5.x
* versions of H2. Some other functionality may be also enabled or disabled.
* </p>
*/
public static final boolean PREVIEW = Utils.getProperty("h2.preview", false);
/**
* System property <code>h2.allowedClasses</code> (default: *).<br />
* Comma separated list of class names or prefixes.
......@@ -325,23 +335,53 @@ public class SysProperties {
Utils.getProperty("h2.oldStyleOuterJoin", false);
/**
* System property {@code h2.oldResultSetGetObject}, {@code true} by default.
* Return {@code Byte} and {@code Short} instead of {@code Integer} from
* {@code ResultSet#getObject(...)} for {@code TINYINT} and {@code SMALLINT}
* values.
* System property {@code h2.oldResultSetGetObject}, {@code true} by default
* unless {@code h2.preview} is enabled.
* <p>
* If {@code true} return {@code Byte} and {@code Short} from
* {@code ResultSet#getObject(int)} and {@code ResultSet#getObject(String)}
* for {@code TINYINT} and {@code SMALLINT} values.
* </p>
* <p>
* If {@code false} return {@code Integer} for them as specified in JDBC
* specification (see Mapping from JDBC Types to Java Object Types).
* </p>
*/
public static final boolean OLD_RESULT_SET_GET_OBJECT =
Utils.getProperty("h2.oldResultSetGetObject", true);
public static final boolean OLD_RESULT_SET_GET_OBJECT = Utils.getProperty("h2.oldResultSetGetObject", !PREVIEW);
/**
* System property {@code h2.bigDecimalIsDecimal}, {@code true} by default. If
* {@code true} map {@code BigDecimal} to {@code DECIMAL} type, if {@code false}
* map it to {@code NUMERIC} as specified in JDBC specification (see Mapping
* from Java Object Types to JDBC Types).
* System property {@code h2.bigDecimalIsDecimal}, {@code true} by default
* unless {@code h2.preview} is enabled.
* <p>
* If {@code true} map {@code BigDecimal} to {@code DECIMAL} type.
* <p>
* <p>
* If {@code false} map {@code BigDecimal} to {@code NUMERIC} as specified
* in JDBC specification (see Mapping from Java Object Types to JDBC Types).
* </p>
*/
public static final boolean BIG_DECIMAL_IS_DECIMAL =
Utils.getProperty("h2.bigDecimalIsDecimal", true);
public static final boolean BIG_DECIMAL_IS_DECIMAL = Utils.getProperty("h2.bigDecimalIsDecimal", !PREVIEW);
/**
* System property {@code h2.returnOffsetDateTime}, {@code false} by default
* unless {@code h2.preview} is enabled.
* <p>
* If {@code true} {@link java.sql.ResultSet#getObject(int)} and
* {@link java.sql.ResultSet#getObject(String)} return
* {@code TIMESTAMP WITH TIME ZONE} values as
* {@code java.time.OffsetDateTime}.
* </p>
* <p>
* If {@code false} return them as {@code org.h2.api.TimestampWithTimeZone}
* instead.
* </p>
* <p>
* This property has effect only on Java 8 / Android API 26 and later
* versions. Without JSR-310 {@code org.h2.api.TimestampWithTimeZone} is
* used unconditionally.
* </p>
*/
public static final boolean RETURN_OFFSET_DATE_TIME = Utils.getProperty("h2.returnOffsetDateTime", PREVIEW);
/**
* System property {@code h2.unlimitedTimeRange}, {@code false} by default.
......
......@@ -178,7 +178,7 @@ public class JdbcParameterMetaData extends TraceObject implements
if (type == Value.UNKNOWN) {
type = Value.STRING;
}
return DataType.getTypeClassName(type);
return DataType.getTypeClassName(type, false);
} catch (Exception e) {
throw logAndConvert(e);
}
......
......@@ -59,6 +59,7 @@ import org.h2.value.ValueShort;
import org.h2.value.ValueString;
import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone;
/**
* <p>
......@@ -3915,21 +3916,19 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
return type.cast(value.getBytes());
} else if (type == java.sql.Array.class) {
int id = getNextId(TraceObject.ARRAY);
return type.cast(value == ValueNull.INSTANCE ? null : new JdbcArray(conn, value, id));
return type.cast(new JdbcArray(conn, value, id));
} else if (type == Blob.class) {
int id = getNextId(TraceObject.BLOB);
return type.cast(value == ValueNull.INSTANCE
? null : new JdbcBlob(conn, value, JdbcLob.State.WITH_VALUE, id));
return type.cast(new JdbcBlob(conn, value, JdbcLob.State.WITH_VALUE, id));
} else if (type == Clob.class) {
int id = getNextId(TraceObject.CLOB);
return type.cast(value == ValueNull.INSTANCE
? null : new JdbcClob(conn, value, JdbcLob.State.WITH_VALUE, id));
return type.cast(new JdbcClob(conn, value, JdbcLob.State.WITH_VALUE, id));
} else if (type == SQLXML.class) {
int id = getNextId(TraceObject.SQLXML);
return type.cast(value == ValueNull.INSTANCE
? null : new JdbcSQLXML(conn, value, JdbcLob.State.WITH_VALUE, id));
return type.cast(new JdbcSQLXML(conn, value, JdbcLob.State.WITH_VALUE, id));
} else if (type == TimestampWithTimeZone.class) {
return type.cast(value.convertTo(Value.TIMESTAMP_TZ).getObject());
ValueTimestampTimeZone v = (ValueTimestampTimeZone) value.convertTo(Value.TIMESTAMP_TZ);
return type.cast(new TimestampWithTimeZone(v.getDateValue(), v.getTimeNanos(), v.getTimeZoneOffsetMins()));
} else if (DataType.isGeometryClass(type)) {
return type.cast(value.convertTo(Value.GEOMETRY).getObject());
} else if (type == LocalDateTimeUtils.LOCAL_DATE) {
......
......@@ -371,7 +371,7 @@ public class JdbcResultSetMetaData extends TraceObject implements
debugCodeCall("getColumnClassName", column);
checkColumnIndex(column);
int type = result.getColumnType(--column);
return DataType.getTypeClassName(type);
return DataType.getTypeClassName(type, true);
} catch (Exception e) {
throw logAndConvert(e);
}
......
......@@ -2003,7 +2003,7 @@ public class SimpleResultSet implements ResultSet, ResultSetMetaData,
@Override
public String getColumnClassName(int columnIndex) throws SQLException {
int type = DataType.getValueTypeFromResultSet(this, columnIndex);
return DataType.getTypeClassName(type);
return DataType.getTypeClassName(type, true);
}
/**
......
......@@ -431,7 +431,7 @@ public class LocalDateTimeUtils {
* @param offsetDateTime the OffsetDateTime to convert, not {@code null}
* @return the value
*/
public static Value offsetDateTimeToValue(Object offsetDateTime) {
public static ValueTimestampTimeZone offsetDateTimeToValue(Object offsetDateTime) {
try {
Object localDateTime = OFFSET_DATE_TIME_TO_LOCAL_DATE_TIME.invoke(offsetDateTime);
Object localDate = LOCAL_DATE_TIME_TO_LOCAL_DATE.invoke(localDateTime);
......
......@@ -583,9 +583,16 @@ public class DataType {
break;
}
case Value.TIMESTAMP_TZ: {
TimestampWithTimeZone value = (TimestampWithTimeZone) rs.getObject(columnIndex);
v = value == null ? (Value) ValueNull.INSTANCE :
ValueTimestampTimeZone.get(value);
Object obj = rs.getObject(columnIndex);
if (obj == null) {
v = ValueNull.INSTANCE;
} else if (LocalDateTimeUtils.isJava8DateApiPresent()
&& LocalDateTimeUtils.OFFSET_DATE_TIME.isInstance(obj)) {
v = LocalDateTimeUtils.offsetDateTimeToValue(obj);
} else {
TimestampWithTimeZone value = (TimestampWithTimeZone) obj;
v = ValueTimestampTimeZone.get(value);
}
break;
}
case Value.DECIMAL: {
......@@ -740,17 +747,26 @@ public class DataType {
* Get the name of the Java class for the given value type.
*
* @param type the value type
* @param forResultSet return mapping for result set
* @return the class name
*/
public static String getTypeClassName(int type) {
public static String getTypeClassName(int type, boolean forResultSet) {
switch (type) {
case Value.BOOLEAN:
// "java.lang.Boolean";
return Boolean.class.getName();
case Value.BYTE:
if (forResultSet && !SysProperties.OLD_RESULT_SET_GET_OBJECT) {
// "java.lang.Integer";
return Integer.class.getName();
}
// "java.lang.Byte";
return Byte.class.getName();
case Value.SHORT:
if (forResultSet && !SysProperties.OLD_RESULT_SET_GET_OBJECT) {
// "java.lang.Integer";
return Integer.class.getName();
}
// "java.lang.Short";
return Short.class.getName();
case Value.INT:
......@@ -772,6 +788,10 @@ public class DataType {
// "java.sql.Timestamp";
return Timestamp.class.getName();
case Value.TIMESTAMP_TZ:
if (SysProperties.RETURN_OFFSET_DATE_TIME && LocalDateTimeUtils.isJava8DateApiPresent()) {
// "java.time.OffsetDateTime";
return LocalDateTimeUtils.OFFSET_DATE_TIME.getName();
}
// "org.h2.api.TimestampWithTimeZone";
return TimestampWithTimeZone.class.getName();
case Value.BYTES:
......
......@@ -10,8 +10,10 @@ import java.sql.SQLException;
import java.sql.Timestamp;
import org.h2.api.ErrorCode;
import org.h2.api.TimestampWithTimeZone;
import org.h2.engine.SysProperties;
import org.h2.message.DbException;
import org.h2.util.DateTimeUtils;
import org.h2.util.LocalDateTimeUtils;
/**
* Implementation of the TIMESTAMP WITH TIME ZONE data type.
......@@ -273,8 +275,10 @@ public class ValueTimestampTimeZone extends Value {
@Override
public Object getObject() {
return new TimestampWithTimeZone(dateValue, timeNanos,
timeZoneOffsetMins);
if (SysProperties.RETURN_OFFSET_DATE_TIME && LocalDateTimeUtils.isJava8DateApiPresent()) {
return LocalDateTimeUtils.valueToOffsetDateTime(this);
}
return new TimestampWithTimeZone(dateValue, timeNanos, timeZoneOffsetMins);
}
@Override
......
......@@ -35,6 +35,7 @@ import java.util.Objects;
import java.util.SimpleTimeZone;
import java.util.concurrent.TimeUnit;
import org.h2.engine.SysProperties;
import org.h2.jdbc.JdbcConnection;
import org.h2.message.DbException;
import org.h2.store.fs.FilePath;
......@@ -1028,7 +1029,8 @@ public abstract class TestBase {
break;
case Types.SMALLINT:
assertEquals("SMALLINT", typeName);
assertEquals("java.lang.Short", className);
assertEquals(SysProperties.OLD_RESULT_SET_GET_OBJECT ? "java.lang.Short" : "java.lang.Integer",
className);
break;
case Types.TIMESTAMP:
assertEquals("TIMESTAMP", typeName);
......
......@@ -22,6 +22,7 @@ import java.sql.Timestamp;
import java.sql.Types;
import org.h2.api.ErrorCode;
import org.h2.engine.SysProperties;
import org.h2.test.TestBase;
import org.h2.test.TestDb;
......@@ -305,7 +306,8 @@ public class TestUpdatableResultSet extends TestDb {
assertEquals("java.lang.String", meta.getColumnClassName(2));
assertEquals("java.math.BigDecimal", meta.getColumnClassName(3));
assertEquals("java.lang.Boolean", meta.getColumnClassName(4));
assertEquals("java.lang.Byte", meta.getColumnClassName(5));
assertEquals(SysProperties.OLD_RESULT_SET_GET_OBJECT ? "java.lang.Byte" : "java.lang.Integer",
meta.getColumnClassName(5));
assertEquals("[B", meta.getColumnClassName(6));
assertEquals("java.sql.Date", meta.getColumnClassName(7));
assertEquals("java.sql.Time", meta.getColumnClassName(8));
......@@ -314,7 +316,8 @@ public class TestUpdatableResultSet extends TestDb {
assertEquals("java.lang.Float", meta.getColumnClassName(11));
assertEquals("java.lang.Long", meta.getColumnClassName(12));
assertEquals("java.lang.Integer", meta.getColumnClassName(13));
assertEquals("java.lang.Short", meta.getColumnClassName(14));
assertEquals(SysProperties.OLD_RESULT_SET_GET_OBJECT ? "java.lang.Short" : "java.lang.Integer",
meta.getColumnClassName(14));
assertEquals("java.sql.Clob", meta.getColumnClassName(15));
assertEquals("java.sql.Blob", meta.getColumnClassName(16));
rs.moveToInsertRow();
......
......@@ -14,6 +14,7 @@ import java.sql.Statement;
import java.util.TimeZone;
import org.h2.api.TimestampWithTimeZone;
import org.h2.engine.SysProperties;
import org.h2.test.TestBase;
import org.h2.test.TestDb;
import org.h2.util.DateTimeUtils;
......@@ -64,7 +65,7 @@ public class TestTimeStampWithTimeZone extends TestDb {
ResultSet rs = stat.executeQuery("select t1 from test");
rs.next();
assertEquals("1970-01-01 12:00:00+00:15", rs.getString(1));
TimestampWithTimeZone ts = (TimestampWithTimeZone) rs.getObject(1);
TimestampWithTimeZone ts = test1_getTimestamp(rs);
assertEquals(1970, ts.getYear());
assertEquals(1, ts.getMonth());
assertEquals(1, ts.getDay());
......@@ -76,7 +77,7 @@ public class TestTimeStampWithTimeZone extends TestDb {
LocalDateTimeUtils.OFFSET_DATE_TIME).toString());
}
rs.next();
ts = (TimestampWithTimeZone) rs.getObject(1);
ts = test1_getTimestamp(rs);
assertEquals(2016, ts.getYear());
assertEquals(9, ts.getMonth());
assertEquals(24, ts.getDay());
......@@ -87,7 +88,7 @@ public class TestTimeStampWithTimeZone extends TestDb {
LocalDateTimeUtils.OFFSET_DATE_TIME).toString());
}
rs.next();
ts = (TimestampWithTimeZone) rs.getObject(1);
ts = test1_getTimestamp(rs);
assertEquals(2016, ts.getYear());
assertEquals(9, ts.getMonth());
assertEquals(24, ts.getDay());
......@@ -98,7 +99,7 @@ public class TestTimeStampWithTimeZone extends TestDb {
LocalDateTimeUtils.OFFSET_DATE_TIME).toString());
}
rs.next();
ts = (TimestampWithTimeZone) rs.getObject(1);
ts = test1_getTimestamp(rs);
assertEquals(2016, ts.getYear());
assertEquals(1, ts.getMonth());
assertEquals(1, ts.getDay());
......@@ -107,7 +108,7 @@ public class TestTimeStampWithTimeZone extends TestDb {
LocalDateTimeUtils.OFFSET_DATE_TIME).toString());
}
rs.next();
ts = (TimestampWithTimeZone) rs.getObject(1);
ts = test1_getTimestamp(rs);
assertEquals(2015, ts.getYear());
assertEquals(12, ts.getMonth());
assertEquals(31, ts.getDay());
......@@ -124,6 +125,11 @@ public class TestTimeStampWithTimeZone extends TestDb {
// Types.TIMESTAMP_WITH_TIMEZONE
// once Java 1.8 is required.
assertEquals(2014, columnType);
if (SysProperties.RETURN_OFFSET_DATE_TIME && LocalDateTimeUtils.isJava8DateApiPresent()) {
assertEquals("java.time.OffsetDateTime", metaData.getColumnClassName(1));
} else {
assertEquals("org.h2.api.TimestampWithTimeZone", metaData.getColumnClassName(1));
}
rs.close();
......@@ -135,6 +141,16 @@ public class TestTimeStampWithTimeZone extends TestDb {
conn.close();
}
private static TimestampWithTimeZone test1_getTimestamp(ResultSet rs) throws SQLException {
Object o = rs.getObject(1);
if (SysProperties.RETURN_OFFSET_DATE_TIME && LocalDateTimeUtils.isJava8DateApiPresent()) {
ValueTimestampTimeZone value = LocalDateTimeUtils.offsetDateTimeToValue(o);
return new TimestampWithTimeZone(value.getDateValue(), value.getTimeNanos(),
value.getTimeZoneOffsetMins());
}
return (TimestampWithTimeZone) o;
}
private void test2() {
ValueTimestampTimeZone a = ValueTimestampTimeZone.parse("1970-01-01 12:00:00.00+00:15");
ValueTimestampTimeZone b = ValueTimestampTimeZone.parse("1970-01-01 12:00:01.00+01:15");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论