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

Merge pull request #1181 from katzyn/current_timestamp

Improve CURRENT_TIMESTAMP and add LOCALTIME and LOCALTIMESTAMP
......@@ -3944,24 +3944,45 @@ CURRENT_DATE()
"
"Functions (Time and Date)","CURRENT_TIME","
{ CURRENT_TIME [ () ] | CURTIME() }
{ CURRENT_TIME [ ( [ int ] ) ] | LOCALTIME [ ( [ int ] ) ] | CURTIME() }
","
Returns the current time.
This method always returns the same value within a transaction.
If fractional seconds precision is specified it should be from 0 to 9, 0 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.
These methods always return the same value within a transaction.
","
CURRENT_TIME()
"
"Functions (Time and Date)","CURRENT_TIMESTAMP","
{ CURRENT_TIMESTAMP [ ( [ int ] ) ] | NOW( [ int ] ) }
CURRENT_TIMESTAMP [ ( [ int ] ) ]
","
Returns the current timestamp.
The precision parameter for nanoseconds precision is optional.
Returns the current timestamp with time zone.
Time zone offset is set to a current time zone offset
If fractional seconds precision is specified it should be from 0 to 9, 6 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.
This method always returns the same value within a transaction.
","
CURRENT_TIMESTAMP()
"
"Functions (Time and Date)","LOCALTIMESTAMP","
{ LOCALTIMESTAMP [ ( [ int ] ) ] | NOW( [ int ] ) }
","
Returns the current timestamp.
If fractional seconds precision is specified it should be from 0 to 9, 6 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.
These methods always return the same value within a transaction.
","
LOCALTIMESTAMP()
"
"Functions (Time and Date)","DATEADD","
{ DATEADD| TIMESTAMPADD } (datetimeField, addIntLong, dateAndTime)
","
......
......@@ -504,8 +504,9 @@ unless they are quoted (surrounded with double quotes). The list is currently:
<code>
ALL, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, DISTINCT, EXCEPT,
EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, HAVING, INNER, INTERSECT, INTERSECTS,
IS, JOIN, LIKE, LIMIT, MINUS, NATURAL, NOT, NULL, OFFSET, ON, ORDER, PRIMARY, ROWNUM, SELECT,
SYSDATE, SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, WHERE, WITH
IS, JOIN, LIKE, LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL, OFFSET, ON, ORDER,
PRIMARY, ROWNUM, SELECT, SYSDATE, SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, WHERE,
WITH
</code>
</p><p>
Certain words of this list are keywords because they are functions that can be used without '()' for compatibility,
......
/*
* 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() {
}
}
......@@ -3148,6 +3148,8 @@ public class Parser {
r = readFunctionWithoutParameters("USER");
} else if (equalsToken("CURRENT_TIMESTAMP", name)) {
r = readFunctionWithoutParameters("CURRENT_TIMESTAMP");
} else if (equalsToken("LOCALTIMESTAMP", name)) {
r = readFunctionWithoutParameters("LOCALTIMESTAMP");
} else if (equalsToken("SYSDATE", name)) {
r = readFunctionWithoutParameters("CURRENT_TIMESTAMP");
} else if (equalsToken("SYSTIMESTAMP", name)) {
......@@ -3158,6 +3160,8 @@ public class Parser {
r = readFunctionWithoutParameters("CURRENT_DATE");
} else if (equalsToken("CURRENT_TIME", name)) {
r = readFunctionWithoutParameters("CURRENT_TIME");
} else if (equalsToken("LOCALTIME", name)) {
r = readFunctionWithoutParameters("LOCALTIME");
} else if (equalsToken("SYSTIME", name)) {
r = readFunctionWithoutParameters("CURRENT_TIME");
} else if (equalsToken("CURRENT", name)) {
......
......@@ -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;
}
......
......@@ -98,7 +98,7 @@ public class Function extends Expression implements FunctionCall {
public static final int CURDATE = 100, CURTIME = 101, DATE_ADD = 102,
DATE_DIFF = 103, DAY_NAME = 104, DAY_OF_MONTH = 105,
DAY_OF_WEEK = 106, DAY_OF_YEAR = 107, HOUR = 108, MINUTE = 109,
MONTH = 110, MONTH_NAME = 111, NOW = 112, QUARTER = 113,
MONTH = 110, MONTH_NAME = 111, LOCALTIMESTAMP = 112, QUARTER = 113,
SECOND = 114, WEEK = 115, YEAR = 116, CURRENT_DATE = 117,
CURRENT_TIME = 118, CURRENT_TIMESTAMP = 119, EXTRACT = 120,
FORMATDATETIME = 121, PARSEDATETIME = 122, ISO_YEAR = 123,
......@@ -294,18 +294,22 @@ public class Function extends Expression implements FunctionCall {
addFunctionNotDeterministic("GETDATE", CURDATE,
0, Value.DATE);
addFunctionNotDeterministic("CURRENT_TIME", CURRENT_TIME,
0, Value.TIME);
VAR_ARGS, Value.TIME);
addFunctionNotDeterministic("LOCALTIME", CURRENT_TIME,
VAR_ARGS, Value.TIME);
addFunctionNotDeterministic("SYSTIME", CURRENT_TIME,
0, Value.TIME);
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_TZ);
addFunctionNotDeterministic("LOCALTIMESTAMP", LOCALTIMESTAMP,
VAR_ARGS, Value.TIMESTAMP);
addFunctionNotDeterministic("NOW", NOW,
addFunctionNotDeterministic("NOW", LOCALTIMESTAMP,
VAR_ARGS, Value.TIMESTAMP);
addFunction("DATEADD", DATE_ADD,
3, Value.TIMESTAMP);
......@@ -823,28 +827,23 @@ 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);
ValueTime vt = (ValueTime) session.getTransactionStart().convertTo(Value.TIME);
result = vt.convertScale(false, v0 == null ? 0 : 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());
case LOCALTIMESTAMP: {
Value vt = session.getTransactionStart().convertTo(Value.TIMESTAMP);
result = vt.convertScale(false, v0 == null ? 6 : v0.getInt());
break;
}
result = vt;
case CURRENT_TIMESTAMP: {
ValueTimestampTimeZone vt = session.getTransactionStart();
result = vt.convertScale(false, v0 == null ? 6 : v0.getInt());
break;
}
case DATABASE:
......@@ -2067,7 +2066,8 @@ public class Function extends Expression implements FunctionCall {
case GREATEST:
min = 1;
break;
case NOW:
case LOCALTIMESTAMP:
case CURRENT_TIME:
case CURRENT_TIMESTAMP:
case RAND:
max = 1;
......
......@@ -1545,9 +1545,10 @@ public class JdbcDatabaseMetaData extends TraceObject implements
* <pre>
* ALL, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP,
* DISTINCT, EXCEPT, EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP,
* HAVING, INNER, INTERSECT, INTERSECTS, IS, JOIN, LIKE, LIMIT, MINUS, NATURAL,
* NOT, NULL, OFFSET, ON, ORDER, PRIMARY, ROWNUM, SELECT, SYSDATE, SYSTIME,
* SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, WHERE, WITH
* HAVING, INNER, INTERSECT, INTERSECTS, IS, JOIN, LIKE, LIMIT, LOCALTIME,
* LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL, OFFSET, ON, ORDER, PRIMARY, ROWNUM,
* SELECT, SYSDATE, SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, WHERE,
* WITH
* </pre>
*
* @return a list of additional the keywords
......
......@@ -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);
......
......@@ -147,10 +147,15 @@ public class ParserUtil {
case 'J':
return getKeywordOrIdentifier(s, "JOIN", KEYWORD);
case 'L':
if ("LIMIT".equals(s)) {
if ("LIMIT".equals(s) || "LIKE".equals(s)) {
return KEYWORD;
}
return getKeywordOrIdentifier(s, "LIKE", KEYWORD);
if (additionalKeywords) {
if ("LOCALTIME".equals(s) || "LOCALTIMESTAMP".equals(s)) {
return KEYWORD;
}
}
return IDENTIFIER;
case 'M':
return getKeywordOrIdentifier(s, "MINUS", KEYWORD);
case 'N':
......
......@@ -21,3 +21,12 @@ select length(now())>18 c1, length(current_timestamp())>18 c2, length(now(0))>18
> ---- ---- ---- ----
> TRUE TRUE TRUE TRUE
> rows: 1
SELECT CAST(CURRENT_TIME AS TIME(9)) = LOCALTIME;
>> TRUE
SELECT CAST(CURRENT_TIME(0) AS TIME(9)) = LOCALTIME(0);
>> TRUE
SELECT CAST(CURRENT_TIME(9) AS TIME(9)) = LOCALTIME(9);
>> TRUE
......@@ -2,3 +2,12 @@
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
SELECT CAST(CURRENT_TIMESTAMP AS TIMESTAMP(9)) = LOCALTIMESTAMP;
>> TRUE
SELECT CAST(CURRENT_TIMESTAMP(0) AS TIMESTAMP(9)) = LOCALTIMESTAMP(0);
>> TRUE
SELECT CAST(CURRENT_TIMESTAMP(9) AS TIMESTAMP(9)) = LOCALTIMESTAMP(9);
>> TRUE
......@@ -501,9 +501,14 @@ public class Build extends BuildBase {
/**
* Add META-INF/versions for Java 9+.
*
* @param includeCurrentTimestamp include CurrentTimestamp implementation
*/
private void addVersions() {
private void addVersions(boolean includeCurrentTimestamp) {
copy("temp/META-INF/versions/9", files("src/java9/precompiled"), "src/java9/precompiled");
if (!includeCurrentTimestamp) {
delete(files("temp/META-INF/versions/9/org/h2/util/CurrentTimestamp.class"));
}
}
/**
......@@ -512,7 +517,7 @@ public class Build extends BuildBase {
@Description(summary = "Create the regular h2.jar file.")
public void jar() {
compile();
addVersions();
addVersions(true);
manifest("H2 Database Engine", "org.h2.tools.Console");
FileList files = files("temp").
exclude("temp/android/*").
......@@ -577,7 +582,7 @@ public class Build extends BuildBase {
@Description(summary = "Create h2client.jar with only the remote JDBC implementation.")
public void jarClient() {
compile(true, true, false);
addVersions();
addVersions(false);
FileList files = files("temp").
exclude("temp/org/h2/build/*").
exclude("temp/org/h2/dev/*").
......@@ -604,7 +609,7 @@ public class Build extends BuildBase {
@Description(summary = "Create h2mvstore.jar containing only the MVStore.")
public void jarMVStore() {
compileMVStore(true);
addVersions();
addVersions(false);
manifestMVStore();
FileList files = files("temp");
files.exclude("*.DS_Store");
......@@ -619,7 +624,7 @@ public class Build extends BuildBase {
@Description(summary = "Create h2small.jar containing only the embedded database.")
public void jarSmall() {
compile(false, false, true);
addVersions();
addVersions(true);
FileList files = files("temp").
exclude("temp/android/*").
exclude("temp/org/h2/android/*").
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论