提交 f651bc69 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Improve precision of CURRENT_TIMESTAMP on Java 9+ and change its return type to…

Improve precision of CURRENT_TIMESTAMP on Java 9+ and change its return type to required by standard
上级 52dec4ac
...@@ -3956,8 +3956,13 @@ CURRENT_TIME() ...@@ -3956,8 +3956,13 @@ CURRENT_TIME()
{ CURRENT_TIMESTAMP [ ( [ int ] ) ] | NOW( [ int ] ) } { CURRENT_TIMESTAMP [ ( [ int ] ) ] | NOW( [ int ] ) }
"," ","
Returns the current timestamp. Returns the current timestamp.
The precision parameter for nanoseconds precision is optional. If fractional seconds precision is specified it should be from 0 to 9, 9 is default.
This method always returns the same value within a transaction. The specified value can be used only to limit precision of a result.
The actual maximum available precision depends on operating system and JVM and can be 3 (milliseconds) or higher.
Higher precision is not available before Java 9.
CURRENT_TIMESTAMP returns timestamp with time zone, its time zone offset is set to a current time zone offset.
NOW() returns the local timestamp without time zone information.
These methods always return the same value within a transaction.
"," ","
CURRENT_TIMESTAMP() CURRENT_TIMESTAMP()
" "
......
/*
* Copyright 2004-2018 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.util;
import java.time.Instant;
import org.h2.value.ValueTimestampTimeZone;
public final class CurrentTimestamp {
/**
* Returns current timestamp.
*
* @return current timestamp
*/
public static ValueTimestampTimeZone get() {
Instant now = Instant.now();
long second = now.getEpochSecond();
int nano = now.getNano();
/*
* This code intentionally does not support properly dates before UNIX
* epoch and time zone offsets with seconds because such support is not
* required for current dates.
*/
int offsetSec = DateTimeUtils.getTimeZone().getOffset(second * 1_000 + nano / 1_000_000) / 1000;
second += offsetSec;
return ValueTimestampTimeZone.fromDateValueAndNanos(
DateTimeUtils.dateValueFromAbsoluteDay(second / DateTimeUtils.SECONDS_PER_DAY),
second % DateTimeUtils.SECONDS_PER_DAY * 1_000_000_000 + nano, (short) (offsetSec / 60));
}
private CurrentTimestamp() {
}
}
...@@ -48,6 +48,7 @@ import org.h2.table.Table; ...@@ -48,6 +48,7 @@ import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.table.TableType; import org.h2.table.TableType;
import org.h2.util.ColumnNamerConfiguration; import org.h2.util.ColumnNamerConfiguration;
import org.h2.util.CurrentTimestamp;
import org.h2.util.SmallLRUCache; import org.h2.util.SmallLRUCache;
import org.h2.util.Utils; import org.h2.util.Utils;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -55,6 +56,7 @@ import org.h2.value.ValueArray; ...@@ -55,6 +56,7 @@ import org.h2.value.ValueArray;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
import org.h2.value.ValueString; import org.h2.value.ValueString;
import org.h2.value.ValueTimestampTimeZone;
/** /**
* A session represents an embedded database connection. When using the server * A session represents an embedded database connection. When using the server
...@@ -114,7 +116,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -114,7 +116,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
private volatile long cancelAtNs; private volatile long cancelAtNs;
private boolean closed; private boolean closed;
private final long sessionStart = System.currentTimeMillis(); private final long sessionStart = System.currentTimeMillis();
private long transactionStart; private ValueTimestampTimeZone transactionStart;
private long currentCommandStart; private long currentCommandStart;
private HashMap<String, Value> variables; private HashMap<String, Value> variables;
private HashSet<ResultInterface> temporaryResults; private HashSet<ResultInterface> temporaryResults;
...@@ -666,7 +668,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -666,7 +668,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
tablesToAnalyze = null; tablesToAnalyze = null;
currentTransactionName = null; currentTransactionName = null;
transactionStart = 0; transactionStart = null;
if (transaction != null) { if (transaction != null) {
try { try {
// increment the data mod count, so that other sessions // increment the data mod count, so that other sessions
...@@ -773,7 +775,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -773,7 +775,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
public void rollback() { public void rollback() {
checkCommitRollback(); checkCommitRollback();
currentTransactionName = null; currentTransactionName = null;
transactionStart = 0; transactionStart = null;
boolean needCommit = undoLog.size() > 0 || transaction != null; boolean needCommit = undoLog.size() > 0 || transaction != null;
if(needCommit) { if(needCommit) {
rollbackTo(null, false); rollbackTo(null, false);
...@@ -1128,7 +1130,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -1128,7 +1130,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
public void rollbackToSavepoint(String name) { public void rollbackToSavepoint(String name) {
checkCommitRollback(); checkCommitRollback();
currentTransactionName = null; currentTransactionName = null;
transactionStart = 0; transactionStart = null;
if (savepoints == null) { if (savepoints == null) {
throw DbException.get(ErrorCode.SAVEPOINT_IS_INVALID_1, name); throw DbException.get(ErrorCode.SAVEPOINT_IS_INVALID_1, name);
} }
...@@ -1453,9 +1455,9 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -1453,9 +1455,9 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
return sessionStart; return sessionStart;
} }
public long getTransactionStart() { public ValueTimestampTimeZone getTransactionStart() {
if (transactionStart == 0) { if (transactionStart == null) {
transactionStart = System.currentTimeMillis(); transactionStart = CurrentTimestamp.get();
} }
return transactionStart; return transactionStart;
} }
......
...@@ -63,7 +63,6 @@ import org.h2.value.ValueLong; ...@@ -63,7 +63,6 @@ import org.h2.value.ValueLong;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
import org.h2.value.ValueResultSet; import org.h2.value.ValueResultSet;
import org.h2.value.ValueString; import org.h2.value.ValueString;
import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone; import org.h2.value.ValueTimestampTimeZone;
import org.h2.value.ValueUuid; import org.h2.value.ValueUuid;
...@@ -300,11 +299,11 @@ public class Function extends Expression implements FunctionCall { ...@@ -300,11 +299,11 @@ public class Function extends Expression implements FunctionCall {
addFunctionNotDeterministic("CURTIME", CURTIME, addFunctionNotDeterministic("CURTIME", CURTIME,
0, Value.TIME); 0, Value.TIME);
addFunctionNotDeterministic("CURRENT_TIMESTAMP", CURRENT_TIMESTAMP, addFunctionNotDeterministic("CURRENT_TIMESTAMP", CURRENT_TIMESTAMP,
VAR_ARGS, Value.TIMESTAMP); VAR_ARGS, Value.TIMESTAMP_TZ);
addFunctionNotDeterministic("SYSDATE", CURRENT_TIMESTAMP, addFunctionNotDeterministic("SYSDATE", CURRENT_TIMESTAMP,
VAR_ARGS, Value.TIMESTAMP); VAR_ARGS, Value.TIMESTAMP_TZ);
addFunctionNotDeterministic("SYSTIMESTAMP", CURRENT_TIMESTAMP, addFunctionNotDeterministic("SYSTIMESTAMP", CURRENT_TIMESTAMP,
VAR_ARGS, Value.TIMESTAMP); VAR_ARGS, Value.TIMESTAMP_TZ);
addFunctionNotDeterministic("NOW", NOW, addFunctionNotDeterministic("NOW", NOW,
VAR_ARGS, Value.TIMESTAMP); VAR_ARGS, Value.TIMESTAMP);
addFunction("DATEADD", DATE_ADD, addFunction("DATEADD", DATE_ADD,
...@@ -823,28 +822,22 @@ public class Function extends Expression implements FunctionCall { ...@@ -823,28 +822,22 @@ public class Function extends Expression implements FunctionCall {
} }
case CURDATE: case CURDATE:
case CURRENT_DATE: { case CURRENT_DATE: {
long now = session.getTransactionStart(); result = session.getTransactionStart().convertTo(Value.DATE);
// need to normalize
result = ValueDate.fromMillis(now);
break; break;
} }
case CURTIME: case CURTIME:
case CURRENT_TIME: { case CURRENT_TIME: {
long now = session.getTransactionStart(); result = session.getTransactionStart().convertTo(Value.TIME);
// need to normalize break;
result = ValueTime.fromMillis(now); }
case NOW: {
Value vt = session.getTransactionStart().convertTo(Value.TIMESTAMP);
result = v0 == null ? vt : vt.convertScale(false, v0.getInt());
break; break;
} }
case NOW:
case CURRENT_TIMESTAMP: { case CURRENT_TIMESTAMP: {
long now = session.getTransactionStart(); ValueTimestampTimeZone vt = session.getTransactionStart();
ValueTimestamp vt = ValueTimestamp.fromMillis(now); result = v0 == null ? vt : vt.convertScale(false, v0.getInt());
if (v0 != null) {
Mode mode = database.getMode();
vt = (ValueTimestamp) vt.convertScale(
mode.convertOnlyToSmallerScale, v0.getInt());
}
result = vt;
break; break;
} }
case DATABASE: case DATABASE:
......
...@@ -21,20 +21,16 @@ import org.h2.message.DbException; ...@@ -21,20 +21,16 @@ import org.h2.message.DbException;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.schema.Sequence; import org.h2.schema.Sequence;
import org.h2.util.DateTimeUtils;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueDate;
import org.h2.value.ValueEnum; import org.h2.value.ValueEnum;
import org.h2.value.ValueInt; import org.h2.value.ValueInt;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
import org.h2.value.ValueNull; 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.ValueTimestampTimeZone;
import org.h2.value.ValueUuid; import org.h2.value.ValueUuid;
/** /**
...@@ -361,16 +357,13 @@ public class Column { ...@@ -361,16 +357,13 @@ public class Column {
if (dt.decimal) { if (dt.decimal) {
value = ValueInt.get(0).convertTo(type); value = ValueInt.get(0).convertTo(type);
} else if (dt.type == Value.TIMESTAMP) { } else if (dt.type == Value.TIMESTAMP) {
value = ValueTimestamp.fromMillis(session.getTransactionStart()); value = session.getTransactionStart().convertTo(Value.TIMESTAMP);
} else if (dt.type == Value.TIMESTAMP_TZ) { } else if (dt.type == Value.TIMESTAMP_TZ) {
long ms = session.getTransactionStart(); value = session.getTransactionStart();
value = ValueTimestampTimeZone.fromDateValueAndNanos(
DateTimeUtils.dateValueFromDate(ms),
DateTimeUtils.nanosFromDate(ms), (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) {
value = ValueDate.fromMillis(session.getTransactionStart()); value = session.getTransactionStart().convertTo(Value.DATE);
} else { } else {
value = ValueString.get("").convertTo(type); value = ValueString.get("").convertTo(type);
} }
......
/*
* Copyright 2004-2018 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.util;
import org.h2.value.ValueTimestampTimeZone;
public final class CurrentTimestamp {
/*
* Signatures of methods should match with
* h2/src/java9/src/org/h2/util/CurrentTimestamp.java and precompiled
* h2/src/java9/precompiled/org/h2/util/CurrentTimestamp.class.
*/
/**
* Returns current timestamp.
*
* @return current timestamp
*/
public static ValueTimestampTimeZone get() {
long ms = System.currentTimeMillis();
/*
* This code intentionally does not support properly dates before UNIX
* epoch and time zone offsets with seconds because such support is not
* required for current dates.
*/
int offset = DateTimeUtils.getTimeZone().getOffset(ms);
ms += offset;
return ValueTimestampTimeZone.fromDateValueAndNanos(
DateTimeUtils.dateValueFromAbsoluteDay(ms / DateTimeUtils.MILLIS_PER_DAY),
ms % DateTimeUtils.MILLIS_PER_DAY * 1_000_000, (short) (offset / 60_000));
}
private CurrentTimestamp() {
}
}
...@@ -112,7 +112,7 @@ public class DateTimeUtils { ...@@ -112,7 +112,7 @@ public class DateTimeUtils {
* *
* @return local time zone * @return local time zone
*/ */
private static TimeZone getTimeZone() { static TimeZone getTimeZone() {
TimeZone tz = timeZone; TimeZone tz = timeZone;
if (tz == null) { if (tz == null) {
timeZone = tz = TimeZone.getDefault(); timeZone = tz = TimeZone.getDefault();
...@@ -506,7 +506,7 @@ public class DateTimeUtils { ...@@ -506,7 +506,7 @@ public class DateTimeUtils {
if (withTimeZone) { if (withTimeZone) {
if (tz != UTC) { if (tz != UTC) {
long millis = convertDateTimeValueToMillis(tz, dateValue, nanos / 1_000_000); long millis = convertDateTimeValueToMillis(tz, dateValue, nanos / 1_000_000);
tzMinutes = (short) (tz.getOffset(millis) / 1000 / 60); tzMinutes = (short) (tz.getOffset(millis) / 60_000);
} }
} else { } else {
long millis = convertDateTimeValueToMillis(tz, dateValue, nanos / 1_000_000); long millis = convertDateTimeValueToMillis(tz, dateValue, nanos / 1_000_000);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论