提交 7224c100 authored 作者: Noel Grandin's avatar Noel Grandin

Experimental support for datatype TIMESTAMP WITH TIMEZONE

上级 86792ec9
...@@ -21,6 +21,8 @@ Change Log ...@@ -21,6 +21,8 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>Experimental support for datatype TIMESTAMP WITH TIMEZONE
</li>
<li>Add support for ALTER TABLE ... RENAME CONSTRAINT .. TO ... <li>Add support for ALTER TABLE ... RENAME CONSTRAINT .. TO ...
</li> </li>
<li>Add support for PostgreSQL ALTER TABLE ... RENAME COLUMN .. TO ... <li>Add support for PostgreSQL ALTER TABLE ... RENAME COLUMN .. TO ...
......
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.api;
import java.sql.Timestamp;
/**
* Extends java.sql.Timestamp to add our time zone information.
*
*/
public class TimestampWithTimeZone extends Timestamp {
/**
* Time zone offset from UTC in minutes, range of -12hours to +12hours
*/
private final short timeZoneOffsetMins;
public TimestampWithTimeZone(long time_ms, int nanos, short timeZoneOffsetMins) {
super(time_ms);
setNanos(nanos);
this.timeZoneOffsetMins = timeZoneOffsetMins;
}
/**
* The timezone offset in minutes.
*
* @return the offset
*/
public short getTimeZoneOffsetMins() {
return timeZoneOffsetMins;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + timeZoneOffsetMins;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
TimestampWithTimeZone other = (TimestampWithTimeZone) obj;
if (timeZoneOffsetMins != other.timeZoneOffsetMins)
return false;
return true;
}
}
...@@ -4033,6 +4033,11 @@ public class Parser { ...@@ -4033,6 +4033,11 @@ public class Parser {
if (readIf("VARYING")) { if (readIf("VARYING")) {
original += " VARYING"; original += " VARYING";
} }
} else if (readIf("TIMESTAMP")) {
if (readIf("WITH")) {
read("TIMEZONE");
original += " WITH TIMEZONE";
}
} else { } else {
regular = true; regular = true;
} }
......
...@@ -28,7 +28,6 @@ import java.sql.Struct; ...@@ -28,7 +28,6 @@ import java.sql.Struct;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.engine.ConnectionInfo; import org.h2.engine.ConnectionInfo;
......
...@@ -45,6 +45,7 @@ import org.h2.value.ValueStringFixed; ...@@ -45,6 +45,7 @@ import org.h2.value.ValueStringFixed;
import org.h2.value.ValueStringIgnoreCase; import org.h2.value.ValueStringIgnoreCase;
import org.h2.value.ValueTime; import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone;
import org.h2.value.ValueTimestampUtc; import org.h2.value.ValueTimestampUtc;
import org.h2.value.ValueUuid; import org.h2.value.ValueUuid;
...@@ -283,6 +284,19 @@ public class ValueDataType implements DataType { ...@@ -283,6 +284,19 @@ public class ValueDataType implements DataType {
buff.put((byte) type).putVarLong(dateTimeValue); buff.put((byte) type).putVarLong(dateTimeValue);
break; break;
} }
case Value.TIMESTAMP_TZ: {
ValueTimestampTimeZone ts = (ValueTimestampTimeZone) v;
long dateValue = ts.getDateValue();
long nanos = ts.getTimeNanos();
long millis = nanos / 1000000;
nanos -= millis * 1000000;
buff.put((byte) type).
putVarLong(dateValue).
putVarLong(millis).
putVarLong(nanos).
putVarInt(ts.getTimeZoneOffsetMins());
break;
}
case Value.JAVA_OBJECT: { case Value.JAVA_OBJECT: {
byte[] b = v.getBytesNoCopy(); byte[] b = v.getBytesNoCopy();
buff.put((byte) type). buff.put((byte) type).
...@@ -492,6 +506,12 @@ public class ValueDataType implements DataType { ...@@ -492,6 +506,12 @@ public class ValueDataType implements DataType {
long dateTimeValue = readVarLong(buff); long dateTimeValue = readVarLong(buff);
return ValueTimestampUtc.fromNanos(dateTimeValue); return ValueTimestampUtc.fromNanos(dateTimeValue);
} }
case Value.TIMESTAMP_TZ: {
long dateValue = readVarLong(buff);
long nanos = readVarLong(buff) * 1000000 + readVarLong(buff);
short tz = (short) readVarInt(buff);
return ValueTimestampTimeZone.fromDateValueAndNanos(dateValue, nanos, tz);
}
case Value.BYTES: { case Value.BYTES: {
int len = readVarInt(buff); int len = readVarInt(buff);
byte[] b = DataUtils.newBytes(len); byte[] b = DataUtils.newBytes(len);
......
...@@ -49,6 +49,7 @@ import org.h2.value.ValueStringFixed; ...@@ -49,6 +49,7 @@ import org.h2.value.ValueStringFixed;
import org.h2.value.ValueStringIgnoreCase; import org.h2.value.ValueStringIgnoreCase;
import org.h2.value.ValueTime; import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone;
import org.h2.value.ValueTimestampUtc; import org.h2.value.ValueTimestampUtc;
import org.h2.value.ValueUuid; import org.h2.value.ValueUuid;
...@@ -544,6 +545,13 @@ public class Data { ...@@ -544,6 +545,13 @@ public class Data {
writeVarLong(ts.getUtcDateTimeNanos()); writeVarLong(ts.getUtcDateTimeNanos());
break; break;
} }
case Value.TIMESTAMP_TZ: {
ValueTimestampTimeZone ts = (ValueTimestampTimeZone) v;
writeByte((byte) type);
writeVarLong(ts.getDateValue());
writeVarLong(ts.getTimeNanos());
writeVarInt(ts.getTimeZoneOffsetMins());
}
case Value.GEOMETRY: case Value.GEOMETRY:
case Value.JAVA_OBJECT: { case Value.JAVA_OBJECT: {
writeByte((byte) type); writeByte((byte) type);
...@@ -781,6 +789,12 @@ public class Data { ...@@ -781,6 +789,12 @@ public class Data {
case Value.TIMESTAMP_UTC: { case Value.TIMESTAMP_UTC: {
return ValueTimestampUtc.fromNanos(readVarLong()); return ValueTimestampUtc.fromNanos(readVarLong());
} }
case Value.TIMESTAMP_TZ: {
long dateValue = readVarLong();
long nanos = readVarLong();
short tz = (short)readVarInt();
return ValueTimestampTimeZone.fromDateValueAndNanos(dateValue, nanos, tz);
}
case Value.BYTES: { case Value.BYTES: {
int len = readVarInt(); int len = readVarInt();
byte[] b = DataUtils.newBytes(len); byte[] b = DataUtils.newBytes(len);
...@@ -1033,6 +1047,14 @@ public class Data { ...@@ -1033,6 +1047,14 @@ public class Data {
ValueTimestampUtc ts = (ValueTimestampUtc) v; ValueTimestampUtc ts = (ValueTimestampUtc) v;
return 1 + getVarLongLen(ts.getUtcDateTimeNanos()); return 1 + getVarLongLen(ts.getUtcDateTimeNanos());
} }
case Value.TIMESTAMP_TZ: {
ValueTimestampTimeZone ts = (ValueTimestampTimeZone) v;
long dateValue = ts.getDateValue();
long nanos = ts.getTimeNanos();
short tz = ts.getTimeZoneOffsetMins();
return 1 + getVarLongLen(dateValue) + getVarLongLen(nanos) +
getVarIntLen(tz);
}
case Value.GEOMETRY: case Value.GEOMETRY:
case Value.JAVA_OBJECT: { case Value.JAVA_OBJECT: {
byte[] b = v.getBytesNoCopy(); byte[] b = v.getBytesNoCopy();
......
...@@ -31,6 +31,7 @@ import org.h2.value.ValueNull; ...@@ -31,6 +31,7 @@ import org.h2.value.ValueNull;
import org.h2.value.ValueString; import org.h2.value.ValueString;
import org.h2.value.ValueTime; import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone;
import org.h2.value.ValueTimestampUtc; import org.h2.value.ValueTimestampUtc;
import org.h2.value.ValueUuid; import org.h2.value.ValueUuid;
...@@ -296,6 +297,8 @@ public class Column { ...@@ -296,6 +297,8 @@ public class Column {
value = ValueTimestamp.fromMillis(session.getTransactionStart()); value = ValueTimestamp.fromMillis(session.getTransactionStart());
} else if (dt.type == Value.TIMESTAMP_UTC) { } else if (dt.type == Value.TIMESTAMP_UTC) {
value = ValueTimestampUtc.fromMillis(session.getTransactionStart()); value = ValueTimestampUtc.fromMillis(session.getTransactionStart());
} else if (dt.type == Value.TIMESTAMP_TZ) {
value = ValueTimestampTimeZone.fromMillis(session.getTransactionStart(), (short)0);
} else if (dt.type == Value.TIME) { } else if (dt.type == Value.TIME) {
value = ValueTime.fromNanos(0); value = ValueTime.fromNanos(0);
} else if (dt.type == Value.DATE) { } else if (dt.type == Value.DATE) {
......
...@@ -23,6 +23,7 @@ import java.util.ArrayList; ...@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.UUID; import java.util.UUID;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.api.TimestampWithTimeZone;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.SessionInterface; import org.h2.engine.SessionInterface;
import org.h2.engine.SysProperties; import org.h2.engine.SysProperties;
...@@ -321,6 +322,13 @@ public class DataType { ...@@ -321,6 +322,13 @@ public class DataType {
// 24 for ValueTimestampUtc, 32 for java.sql.Timestamp // 24 for ValueTimestampUtc, 32 for java.sql.Timestamp
56 56
); );
add(Value.TIMESTAMP_TZ, Types.OTHER, "TimestampTimeZone",
createDate(ValueTimestampTimeZone.PRECISION, "TIMESTAMP_TZ",
ValueTimestampTimeZone.DEFAULT_SCALE, ValueTimestampTimeZone.DISPLAY_SIZE),
new String[]{"TIMESTAMP WITH TIMEZONE"},
// 26 for ValueTimestampUtc, 32 for java.sql.Timestamp
58
);
add(Value.BYTES, Types.VARBINARY, "Bytes", add(Value.BYTES, Types.VARBINARY, "Bytes",
createString(false), createString(false),
new String[]{"VARBINARY"}, new String[]{"VARBINARY"},
...@@ -551,6 +559,12 @@ public class DataType { ...@@ -551,6 +559,12 @@ public class DataType {
ValueTimestampUtc.fromMillisNanos(value.getTime(), value.getNanos()); ValueTimestampUtc.fromMillisNanos(value.getTime(), value.getNanos());
break; break;
} }
case Value.TIMESTAMP_TZ: {
TimestampWithTimeZone value = (TimestampWithTimeZone) rs.getTimestamp(columnIndex);
v = value == null ? (Value) ValueNull.INSTANCE :
ValueTimestampTimeZone.get(value);
break;
}
case Value.DECIMAL: { case Value.DECIMAL: {
BigDecimal value = rs.getBigDecimal(columnIndex); BigDecimal value = rs.getBigDecimal(columnIndex);
v = value == null ? (Value) ValueNull.INSTANCE : v = value == null ? (Value) ValueNull.INSTANCE :
...@@ -726,6 +740,9 @@ public class DataType { ...@@ -726,6 +740,9 @@ public class DataType {
case Value.TIMESTAMP_UTC: case Value.TIMESTAMP_UTC:
// "java.sql.Timestamp"; // "java.sql.Timestamp";
return Timestamp.class.getName(); return Timestamp.class.getName();
case Value.TIMESTAMP_TZ:
// "org.h2.api.TimestampWithTimeZone";
return TimestampWithTimeZone.class.getName();
case Value.BYTES: case Value.BYTES:
case Value.UUID: case Value.UUID:
// "[B", not "byte[]"; // "[B", not "byte[]";
......
...@@ -392,6 +392,13 @@ public class Transfer { ...@@ -392,6 +392,13 @@ public class Transfer {
writeLong(ts.getUtcDateTimeNanos()); writeLong(ts.getUtcDateTimeNanos());
break; break;
} }
case Value.TIMESTAMP_TZ: {
ValueTimestampTimeZone ts = (ValueTimestampTimeZone) v;
writeLong(ts.getDateValue());
writeLong(ts.getTimeNanos());
writeInt(ts.getTimeZoneOffsetMins());
break;
}
case Value.DECIMAL: case Value.DECIMAL:
writeString(v.getString()); writeString(v.getString());
break; break;
...@@ -581,6 +588,9 @@ public class Transfer { ...@@ -581,6 +588,9 @@ public class Transfer {
case Value.TIMESTAMP_UTC: { case Value.TIMESTAMP_UTC: {
return ValueTimestampUtc.fromNanos(readLong()); return ValueTimestampUtc.fromNanos(readLong());
} }
case Value.TIMESTAMP_TZ: {
return ValueTimestampTimeZone.fromDateValueAndNanos(readLong(), readLong(), (short) readInt());
}
case Value.DECIMAL: case Value.DECIMAL:
return ValueDecimal.get(new BigDecimal(readString())); return ValueDecimal.get(new BigDecimal(readString()));
case Value.DOUBLE: case Value.DOUBLE:
......
...@@ -162,11 +162,15 @@ public abstract class Value { ...@@ -162,11 +162,15 @@ public abstract class Value {
* The value type for TIMESTAMP UTC values. * The value type for TIMESTAMP UTC values.
*/ */
public static final int TIMESTAMP_UTC = 23; public static final int TIMESTAMP_UTC = 23;
/**
* The value type for TIMESTAMP WITH TIMEZONE values.
*/
public static final int TIMESTAMP_TZ = 24;
/** /**
* The number of value types. * The number of value types.
*/ */
public static final int TYPE_COUNT = TIMESTAMP_UTC + 1; public static final int TYPE_COUNT = TIMESTAMP_TZ + 1;
private static SoftReference<Value[]> softCache = private static SoftReference<Value[]> softCache =
new SoftReference<Value[]>(null); new SoftReference<Value[]>(null);
...@@ -304,6 +308,8 @@ public abstract class Value { ...@@ -304,6 +308,8 @@ public abstract class Value {
return 32; return 32;
case TIMESTAMP_UTC: case TIMESTAMP_UTC:
return 33; return 33;
case TIMESTAMP_TZ:
return 34;
case BYTES: case BYTES:
return 40; return 40;
case BLOB: case BLOB:
...@@ -548,6 +554,7 @@ public abstract class Value { ...@@ -548,6 +554,7 @@ public abstract class Value {
case DATE: case DATE:
case TIMESTAMP: case TIMESTAMP:
case TIMESTAMP_UTC: case TIMESTAMP_UTC:
case TIMESTAMP_TZ:
case BYTES: case BYTES:
case JAVA_OBJECT: case JAVA_OBJECT:
case UUID: case UUID:
...@@ -575,6 +582,9 @@ public abstract class Value { ...@@ -575,6 +582,9 @@ public abstract class Value {
return ValueByte.get(convertToByte(convertToLong(getFloat()))); return ValueByte.get(convertToByte(convertToLong(getFloat())));
case BYTES: case BYTES:
return ValueByte.get((byte) Integer.parseInt(getString(), 16)); return ValueByte.get((byte) Integer.parseInt(getString(), 16));
case TIMESTAMP_TZ:
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, getString());
} }
break; break;
} }
...@@ -597,6 +607,9 @@ public abstract class Value { ...@@ -597,6 +607,9 @@ public abstract class Value {
return ValueShort.get(convertToShort(convertToLong(getFloat()))); return ValueShort.get(convertToShort(convertToLong(getFloat())));
case BYTES: case BYTES:
return ValueShort.get((short) Integer.parseInt(getString(), 16)); return ValueShort.get((short) Integer.parseInt(getString(), 16));
case TIMESTAMP_TZ:
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, getString());
} }
break; break;
} }
...@@ -619,6 +632,9 @@ public abstract class Value { ...@@ -619,6 +632,9 @@ public abstract class Value {
return ValueInt.get(convertToInt(convertToLong(getFloat()))); return ValueInt.get(convertToInt(convertToLong(getFloat())));
case BYTES: case BYTES:
return ValueInt.get((int) Long.parseLong(getString(), 16)); return ValueInt.get((int) Long.parseLong(getString(), 16));
case TIMESTAMP_TZ:
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, getString());
} }
break; break;
} }
...@@ -648,6 +664,9 @@ public abstract class Value { ...@@ -648,6 +664,9 @@ public abstract class Value {
} }
case TIMESTAMP_UTC: case TIMESTAMP_UTC:
return ValueLong.get(getLong()); return ValueLong.get(getLong());
case TIMESTAMP_TZ:
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, getString());
} }
break; break;
} }
...@@ -682,6 +701,9 @@ public abstract class Value { ...@@ -682,6 +701,9 @@ public abstract class Value {
// better rounding behavior than BigDecimal.valueOf(f) // better rounding behavior than BigDecimal.valueOf(f)
return ValueDecimal.get(new BigDecimal(Float.toString(f))); return ValueDecimal.get(new BigDecimal(Float.toString(f)));
} }
case TIMESTAMP_TZ:
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, getString());
} }
break; break;
} }
...@@ -702,6 +724,9 @@ public abstract class Value { ...@@ -702,6 +724,9 @@ public abstract class Value {
return ValueDouble.get(getBigDecimal().doubleValue()); return ValueDouble.get(getBigDecimal().doubleValue());
case FLOAT: case FLOAT:
return ValueDouble.get(getFloat()); return ValueDouble.get(getFloat());
case TIMESTAMP_TZ:
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, getString());
} }
break; break;
} }
...@@ -722,6 +747,9 @@ public abstract class Value { ...@@ -722,6 +747,9 @@ public abstract class Value {
return ValueFloat.get(getBigDecimal().floatValue()); return ValueFloat.get(getBigDecimal().floatValue());
case DOUBLE: case DOUBLE:
return ValueFloat.get((float) getDouble()); return ValueFloat.get((float) getDouble());
case TIMESTAMP_TZ:
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, getString());
} }
break; break;
} }
...@@ -738,6 +766,9 @@ public abstract class Value { ...@@ -738,6 +766,9 @@ public abstract class Value {
case TIMESTAMP_UTC: case TIMESTAMP_UTC:
return ValueDate.fromMillis( return ValueDate.fromMillis(
((ValueTimestampUtc) this).getUtcDateTimeMillis()); ((ValueTimestampUtc) this).getUtcDateTimeMillis());
case TIMESTAMP_TZ:
return ValueDate.fromDateValue(
((ValueTimestampTimeZone) this).getDateValue());
} }
break; break;
} }
...@@ -753,6 +784,9 @@ public abstract class Value { ...@@ -753,6 +784,9 @@ public abstract class Value {
case TIMESTAMP_UTC: case TIMESTAMP_UTC:
return ValueTime.fromMillis( return ValueTime.fromMillis(
((ValueTimestampUtc) this).getUtcDateTimeMillis()); ((ValueTimestampUtc) this).getUtcDateTimeMillis());
case TIMESTAMP_TZ:
return ValueTime.fromNanos(
((ValueTimestampTimeZone) this).getTimeNanos());
} }
break; break;
} }
...@@ -768,6 +802,10 @@ public abstract class Value { ...@@ -768,6 +802,10 @@ public abstract class Value {
return ValueTimestamp.fromMillisNanos( return ValueTimestamp.fromMillisNanos(
((ValueTimestampUtc) this).getUtcDateTimeMillis(), ((ValueTimestampUtc) this).getUtcDateTimeMillis(),
((ValueTimestampUtc) this).getNanosSinceLastMillis()); ((ValueTimestampUtc) this).getNanosSinceLastMillis());
case TIMESTAMP_TZ:
return ValueTimestamp.fromDateValueAndNanos(
((ValueTimestampTimeZone) this).getDateValue(),
((ValueTimestampTimeZone) this).getTimeNanos());
} }
break; break;
} }
...@@ -793,6 +831,9 @@ public abstract class Value { ...@@ -793,6 +831,9 @@ public abstract class Value {
return ValueTimestampUtc.fromMillisNanos( return ValueTimestampUtc.fromMillisNanos(
((ValueTimestamp) this).getTimestamp().getTime(), ((ValueTimestamp) this).getTimestamp().getTime(),
((ValueTimestamp) this).getTimestamp().getNanos()); ((ValueTimestamp) this).getTimestamp().getNanos());
case TIMESTAMP_TZ:
// TODO
throw DbException.getUnsupportedException("unimplemented");
} }
break; break;
} }
...@@ -835,6 +876,9 @@ public abstract class Value { ...@@ -835,6 +876,9 @@ public abstract class Value {
(byte) x (byte) x
}); });
} }
case TIMESTAMP_TZ:
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, getString());
} }
break; break;
} }
...@@ -844,6 +888,9 @@ public abstract class Value { ...@@ -844,6 +888,9 @@ public abstract class Value {
case BLOB: case BLOB:
return ValueJavaObject.getNoCopy( return ValueJavaObject.getNoCopy(
null, getBytesNoCopy(), getDataHandler()); null, getBytesNoCopy(), getDataHandler());
case TIMESTAMP_TZ:
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, getString());
} }
break; break;
} }
...@@ -852,6 +899,9 @@ public abstract class Value { ...@@ -852,6 +899,9 @@ public abstract class Value {
case BYTES: case BYTES:
return ValueLobDb.createSmallLob( return ValueLobDb.createSmallLob(
Value.BLOB, getBytesNoCopy()); Value.BLOB, getBytesNoCopy());
case TIMESTAMP_TZ:
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, getString());
} }
break; break;
} }
...@@ -859,6 +909,9 @@ public abstract class Value { ...@@ -859,6 +909,9 @@ public abstract class Value {
switch (getType()) { switch (getType()) {
case BYTES: case BYTES:
return ValueUuid.get(getBytesNoCopy()); return ValueUuid.get(getBytesNoCopy());
case TIMESTAMP_TZ:
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, getString());
} }
} }
case GEOMETRY: case GEOMETRY:
...@@ -870,6 +923,9 @@ public abstract class Value { ...@@ -870,6 +923,9 @@ public abstract class Value {
if (DataType.isGeometry(object)) { if (DataType.isGeometry(object)) {
return ValueGeometry.getFromGeometry(object); return ValueGeometry.getFromGeometry(object);
} }
case TIMESTAMP_TZ:
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, getString());
} }
} }
// conversion by parsing the string value // conversion by parsing the string value
...@@ -911,6 +967,8 @@ public abstract class Value { ...@@ -911,6 +967,8 @@ public abstract class Value {
return ValueTimestamp.parse(s.trim()); return ValueTimestamp.parse(s.trim());
case TIMESTAMP_UTC: case TIMESTAMP_UTC:
return ValueTimestampUtc.parse(s.trim()); return ValueTimestampUtc.parse(s.trim());
case TIMESTAMP_TZ:
return ValueTimestampTimeZone.parse(s.trim());
case BYTES: case BYTES:
return ValueBytes.getNoCopy( return ValueBytes.getNoCopy(
StringUtils.convertHexToBytes(s.trim())); StringUtils.convertHexToBytes(s.trim()));
......
...@@ -24,6 +24,7 @@ import org.h2.test.db.TestCases; ...@@ -24,6 +24,7 @@ import org.h2.test.db.TestCases;
import org.h2.test.db.TestCheckpoint; import org.h2.test.db.TestCheckpoint;
import org.h2.test.db.TestCluster; import org.h2.test.db.TestCluster;
import org.h2.test.db.TestCompatibility; import org.h2.test.db.TestCompatibility;
import org.h2.test.db.TestCompatibilityOracle;
import org.h2.test.db.TestCsv; import org.h2.test.db.TestCsv;
import org.h2.test.db.TestDateStorage; import org.h2.test.db.TestDateStorage;
import org.h2.test.db.TestDeadlock; import org.h2.test.db.TestDeadlock;
...@@ -46,7 +47,6 @@ import org.h2.test.db.TestMultiThread; ...@@ -46,7 +47,6 @@ import org.h2.test.db.TestMultiThread;
import org.h2.test.db.TestMultiThreadedKernel; import org.h2.test.db.TestMultiThreadedKernel;
import org.h2.test.db.TestOpenClose; import org.h2.test.db.TestOpenClose;
import org.h2.test.db.TestOptimizations; import org.h2.test.db.TestOptimizations;
import org.h2.test.db.TestCompatibilityOracle;
import org.h2.test.db.TestOptimizerHints; import org.h2.test.db.TestOptimizerHints;
import org.h2.test.db.TestOutOfMemory; import org.h2.test.db.TestOutOfMemory;
import org.h2.test.db.TestPowerOff; import org.h2.test.db.TestPowerOff;
...@@ -178,8 +178,8 @@ import org.h2.test.unit.TestFileSystem; ...@@ -178,8 +178,8 @@ import org.h2.test.unit.TestFileSystem;
import org.h2.test.unit.TestFtp; import org.h2.test.unit.TestFtp;
import org.h2.test.unit.TestIntArray; import org.h2.test.unit.TestIntArray;
import org.h2.test.unit.TestIntIntHashMap; import org.h2.test.unit.TestIntIntHashMap;
import org.h2.test.unit.TestJmx;
import org.h2.test.unit.TestIntPerfectHash; import org.h2.test.unit.TestIntPerfectHash;
import org.h2.test.unit.TestJmx;
import org.h2.test.unit.TestLocale; import org.h2.test.unit.TestLocale;
import org.h2.test.unit.TestMathUtils; import org.h2.test.unit.TestMathUtils;
import org.h2.test.unit.TestModifyOnWrite; import org.h2.test.unit.TestModifyOnWrite;
...@@ -203,6 +203,8 @@ import org.h2.test.unit.TestSort; ...@@ -203,6 +203,8 @@ import org.h2.test.unit.TestSort;
import org.h2.test.unit.TestStreams; import org.h2.test.unit.TestStreams;
import org.h2.test.unit.TestStringCache; import org.h2.test.unit.TestStringCache;
import org.h2.test.unit.TestStringUtils; import org.h2.test.unit.TestStringUtils;
import org.h2.test.unit.TestTimeStampUtc;
import org.h2.test.unit.TestTimeStampWithTimeZone;
import org.h2.test.unit.TestTools; import org.h2.test.unit.TestTools;
import org.h2.test.unit.TestTraceSystem; import org.h2.test.unit.TestTraceSystem;
import org.h2.test.unit.TestUtils; import org.h2.test.unit.TestUtils;
...@@ -851,6 +853,8 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -851,6 +853,8 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest(new TestSort()); addTest(new TestSort());
addTest(new TestStreams()); addTest(new TestStreams());
addTest(new TestStringUtils()); addTest(new TestStringUtils());
addTest(new TestTimeStampUtc());
addTest(new TestTimeStampWithTimeZone());
addTest(new TestTraceSystem()); addTest(new TestTraceSystem());
addTest(new TestUpgrade()); addTest(new TestUpgrade());
addTest(new TestUsingIndex()); addTest(new TestUsingIndex());
......
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, and the
* EPL 1.0 (http://h2database.com/html/license.html). Initial Developer: H2
* Group
*/
package org.h2.test.unit;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.api.TimestampWithTimeZone;
import org.h2.test.TestBase;
/**
*/
public class TestTimeStampWithTimeZone extends TestBase {
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String... a) throws Exception {
TestBase.createCaller().init().test();
}
@Override
public void test() throws SQLException {
deleteDb("timestamp_tz");
test1();
deleteDb("timestamp_tz");
}
private void test1() throws SQLException {
Connection conn = getConnection("timestamp_tz");
Statement stat = conn.createStatement();
stat.execute("create table test(id identity, t1 timestamp with timezone)");
stat.execute("insert into test(t1) values('1970-01-01 12:00:00.00+00:15')");
ResultSet rs = stat.executeQuery("select t1 from test");
rs.next();
assertTrue(new TimestampWithTimeZone(36000000, 00, (short)15).equals(rs.getTimestamp(1)));
conn.close();
}
}
...@@ -12,7 +12,6 @@ import java.sql.SQLException; ...@@ -12,7 +12,6 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.Random; import java.util.Random;
import org.h2.api.JavaObjectSerializer; import org.h2.api.JavaObjectSerializer;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
...@@ -47,6 +46,7 @@ import org.h2.value.ValueStringFixed; ...@@ -47,6 +46,7 @@ import org.h2.value.ValueStringFixed;
import org.h2.value.ValueStringIgnoreCase; import org.h2.value.ValueStringIgnoreCase;
import org.h2.value.ValueTime; import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone;
import org.h2.value.ValueTimestampUtc; import org.h2.value.ValueTimestampUtc;
import org.h2.value.ValueUuid; import org.h2.value.ValueUuid;
...@@ -166,6 +166,8 @@ public class TestValueMemory extends TestBase implements DataHandler { ...@@ -166,6 +166,8 @@ public class TestValueMemory extends TestBase implements DataHandler {
return ValueTimestamp.fromMillis(random.nextLong()); return ValueTimestamp.fromMillis(random.nextLong());
case Value.TIMESTAMP_UTC: case Value.TIMESTAMP_UTC:
return ValueTimestampUtc.fromMillis(random.nextLong()); return ValueTimestampUtc.fromMillis(random.nextLong());
case Value.TIMESTAMP_TZ:
return ValueTimestampTimeZone.fromMillis(random.nextLong(), (short)0);
case Value.BYTES: case Value.BYTES:
return ValueBytes.get(randomBytes(random.nextInt(1000))); return ValueBytes.get(randomBytes(random.nextInt(1000)));
case Value.STRING: case Value.STRING:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论