提交 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()
{ CURRENT_TIMESTAMP [ ( [ int ] ) ] | NOW( [ int ] ) }
","
Returns the current timestamp.
The precision parameter for nanoseconds precision is optional.
This method always returns the same value within a transaction.
If fractional seconds precision is specified it should be from 0 to 9, 9 is default.
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()
"
......
/*
* 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;
import org.h2.table.TableFilter;
import org.h2.table.TableType;
import org.h2.util.ColumnNamerConfiguration;
import org.h2.util.CurrentTimestamp;
import org.h2.util.SmallLRUCache;
import org.h2.util.Utils;
import org.h2.value.Value;
......@@ -55,6 +56,7 @@ import org.h2.value.ValueArray;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
import org.h2.value.ValueString;
import org.h2.value.ValueTimestampTimeZone;
/**
* A session represents an embedded database connection. When using the server
......@@ -114,7 +116,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
private volatile long cancelAtNs;
private boolean closed;
private final long sessionStart = System.currentTimeMillis();
private long transactionStart;
private ValueTimestampTimeZone transactionStart;
private long currentCommandStart;
private HashMap<String, Value> variables;
private HashSet<ResultInterface> temporaryResults;
......@@ -666,7 +668,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
tablesToAnalyze = null;
currentTransactionName = null;
transactionStart = 0;
transactionStart = null;
if (transaction != null) {
try {
// increment the data mod count, so that other sessions
......@@ -773,7 +775,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
public void rollback() {
checkCommitRollback();
currentTransactionName = null;
transactionStart = 0;
transactionStart = null;
boolean needCommit = undoLog.size() > 0 || transaction != null;
if(needCommit) {
rollbackTo(null, false);
......@@ -1128,7 +1130,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
public void rollbackToSavepoint(String name) {
checkCommitRollback();
currentTransactionName = null;
transactionStart = 0;
transactionStart = null;
if (savepoints == null) {
throw DbException.get(ErrorCode.SAVEPOINT_IS_INVALID_1, name);
}
......@@ -1453,9 +1455,9 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
return sessionStart;
}
public long getTransactionStart() {
if (transactionStart == 0) {
transactionStart = System.currentTimeMillis();
public ValueTimestampTimeZone getTransactionStart() {
if (transactionStart == null) {
transactionStart = CurrentTimestamp.get();
}
return transactionStart;
}
......
......@@ -63,7 +63,6 @@ import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
import org.h2.value.ValueResultSet;
import org.h2.value.ValueString;
import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone;
import org.h2.value.ValueUuid;
......@@ -300,11 +299,11 @@ public class Function extends Expression implements FunctionCall {
addFunctionNotDeterministic("CURTIME", CURTIME,
0, Value.TIME);
addFunctionNotDeterministic("CURRENT_TIMESTAMP", CURRENT_TIMESTAMP,
VAR_ARGS, Value.TIMESTAMP);
VAR_ARGS, Value.TIMESTAMP_TZ);
addFunctionNotDeterministic("SYSDATE", CURRENT_TIMESTAMP,
VAR_ARGS, Value.TIMESTAMP);
VAR_ARGS, Value.TIMESTAMP_TZ);
addFunctionNotDeterministic("SYSTIMESTAMP", CURRENT_TIMESTAMP,
VAR_ARGS, Value.TIMESTAMP);
VAR_ARGS, Value.TIMESTAMP_TZ);
addFunctionNotDeterministic("NOW", NOW,
VAR_ARGS, Value.TIMESTAMP);
addFunction("DATEADD", DATE_ADD,
......@@ -823,28 +822,22 @@ public class Function extends Expression implements FunctionCall {
}
case CURDATE:
case CURRENT_DATE: {
long now = session.getTransactionStart();
// need to normalize
result = ValueDate.fromMillis(now);
result = session.getTransactionStart().convertTo(Value.DATE);
break;
}
case CURTIME:
case CURRENT_TIME: {
long now = session.getTransactionStart();
// need to normalize
result = ValueTime.fromMillis(now);
result = session.getTransactionStart().convertTo(Value.TIME);
break;
}
case NOW: {
Value vt = session.getTransactionStart().convertTo(Value.TIMESTAMP);
result = v0 == null ? vt : vt.convertScale(false, v0.getInt());
break;
}
case NOW:
case CURRENT_TIMESTAMP: {
long now = session.getTransactionStart();
ValueTimestamp vt = ValueTimestamp.fromMillis(now);
if (v0 != null) {
Mode mode = database.getMode();
vt = (ValueTimestamp) vt.convertScale(
mode.convertOnlyToSmallerScale, v0.getInt());
}
result = vt;
ValueTimestampTimeZone vt = session.getTransactionStart();
result = v0 == null ? vt : vt.convertScale(false, v0.getInt());
break;
}
case DATABASE:
......
......@@ -21,20 +21,16 @@ import org.h2.message.DbException;
import org.h2.result.Row;
import org.h2.schema.Schema;
import org.h2.schema.Sequence;
import org.h2.util.DateTimeUtils;
import org.h2.util.MathUtils;
import org.h2.util.StringUtils;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueDate;
import org.h2.value.ValueEnum;
import org.h2.value.ValueInt;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
import org.h2.value.ValueString;
import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone;
import org.h2.value.ValueUuid;
/**
......@@ -361,16 +357,13 @@ public class Column {
if (dt.decimal) {
value = ValueInt.get(0).convertTo(type);
} else if (dt.type == Value.TIMESTAMP) {
value = ValueTimestamp.fromMillis(session.getTransactionStart());
value = session.getTransactionStart().convertTo(Value.TIMESTAMP);
} else if (dt.type == Value.TIMESTAMP_TZ) {
long ms = session.getTransactionStart();
value = ValueTimestampTimeZone.fromDateValueAndNanos(
DateTimeUtils.dateValueFromDate(ms),
DateTimeUtils.nanosFromDate(ms), (short) 0);
value = session.getTransactionStart();
} else if (dt.type == Value.TIME) {
value = ValueTime.fromNanos(0);
} else if (dt.type == Value.DATE) {
value = ValueDate.fromMillis(session.getTransactionStart());
value = session.getTransactionStart().convertTo(Value.DATE);
} else {
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 {
*
* @return local time zone
*/
private static TimeZone getTimeZone() {
static TimeZone getTimeZone() {
TimeZone tz = timeZone;
if (tz == null) {
timeZone = tz = TimeZone.getDefault();
......@@ -506,7 +506,7 @@ public class DateTimeUtils {
if (withTimeZone) {
if (tz != UTC) {
long millis = convertDateTimeValueToMillis(tz, dateValue, nanos / 1_000_000);
tzMinutes = (short) (tz.getOffset(millis) / 1000 / 60);
tzMinutes = (short) (tz.getOffset(millis) / 60_000);
}
} else {
long millis = convertDateTimeValueToMillis(tz, dateValue, nanos / 1_000_000);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论