提交 41af1194 authored 作者: andrei's avatar andrei

Merge remote-tracking branch 'h2database/master' into test_out_of_memory

...@@ -2300,9 +2300,9 @@ Each table has a pseudo-column named ""_ROWID_"" that contains the unique row id ...@@ -2300,9 +2300,9 @@ Each table has a pseudo-column named ""_ROWID_"" that contains the unique row id
" "
"Other Grammar","Time"," "Other Grammar","Time","
TIME 'hh:mm:ss' TIME 'hh:mm:ss[.nnnnnnnnn]'
"," ","
A time literal. A value is between plus and minus 2 million hours A time literal. A value is between 0:00:00 and 23:59:59.999999999
and has nanosecond resolution. and has nanosecond resolution.
"," ","
TIME '23:59:59' TIME '23:59:59'
...@@ -2318,6 +2318,19 @@ minimum and maximum years are 0001 and 9999. ...@@ -2318,6 +2318,19 @@ minimum and maximum years are 0001 and 9999.
TIMESTAMP '2005-12-31 23:59:59' TIMESTAMP '2005-12-31 23:59:59'
" "
"Other Grammar","Timestamp with time zone","
TIMESTAMP 'yyyy-MM-dd hh:mm:ss[.nnnnnnnnn]
[Z | { - | + } timeZoneOffsetString | timeZoneNameString ]'
","
A timestamp with time zone literal.
If name of time zone is specified it will be converted to time zone offset.
","
TIMESTAMP WITH TIME ZONE '2005-12-31 23:59:59Z'
TIMESTAMP WITH TIME ZONE '2005-12-31 23:59:59-10:00'
TIMESTAMP WITH TIME ZONE '2005-12-31 23:59:59.123+05'
TIMESTAMP WITH TIME ZONE '2005-12-31 23:59:59.123456789 Europe/London'
"
"Other Grammar","Value"," "Other Grammar","Value","
string | dollarQuotedString | numeric | date | time | timestamp | boolean | bytes | array | null string | dollarQuotedString | numeric | date | time | timestamp | boolean | bytes | array | null
"," ","
...@@ -3671,7 +3684,7 @@ CURRENT_TIMESTAMP() ...@@ -3671,7 +3684,7 @@ CURRENT_TIMESTAMP()
Adds units to a date-time value. The string indicates the unit. Adds units to a date-time value. The string indicates the unit.
Use negative values to subtract units. Use negative values to subtract units.
addIntLong may be a long value when manipulating milliseconds, addIntLong may be a long value when manipulating milliseconds,
otherwise it's range is restricted to int. microseconds, or nanoseconds otherwise its range is restricted to int.
The same units as in the EXTRACT function are supported. The same units as in the EXTRACT function are supported.
This method returns a value with the same type as specified value if unit is compatible with this value. This method returns a value with the same type as specified value if unit is compatible with this value.
If specified unit is a HOUR, MINUTE, SECOND, MILLISECOND, etc and value is a DATE value DATEADD returns combined TIMESTAMP. If specified unit is a HOUR, MINUTE, SECOND, MILLISECOND, etc and value is a DATE value DATEADD returns combined TIMESTAMP.
...@@ -3727,11 +3740,13 @@ DAY_OF_YEAR(CREATED) ...@@ -3727,11 +3740,13 @@ DAY_OF_YEAR(CREATED)
"Functions (Time and Date)","EXTRACT"," "Functions (Time and Date)","EXTRACT","
EXTRACT ( { YEAR | YY | MONTH | MM | QUARTER | WEEK | ISO_WEEK EXTRACT ( { YEAR | YY | MONTH | MM | QUARTER | WEEK | ISO_WEEK
| DAY | DD | DAY_OF_YEAR | DOY | DAY | DD | DAY_OF_YEAR | DOY
| HOUR | HH | MINUTE | MI | SECOND | SS | MILLISECOND | MS } | HOUR | HH | MINUTE | MI | SECOND | SS | EPOCH
| MILLISECOND | MS | MICROSECOND | MCS | NANOSECOND | NS }
FROM timestamp ) FROM timestamp )
"," ","
Returns a specific value from a timestamps. Returns a specific value from a timestamps.
This method returns an int. This method returns a numeric value with EPOCH unit and
an int for all other time units.
"," ","
EXTRACT(SECOND FROM CURRENT_TIMESTAMP) EXTRACT(SECOND FROM CURRENT_TIMESTAMP)
" "
...@@ -3820,6 +3835,17 @@ This method uses the current system locale. ...@@ -3820,6 +3835,17 @@ This method uses the current system locale.
WEEK(CREATED) WEEK(CREATED)
" "
"Functions (Time and Date)","ISO_WEEK","
ISO_WEEK(timestamp)
","
Returns the week (1-53) from a timestamp.
This method uses the ISO definition when
first week of year should have at least four days
and week is started with Monday.
","
ISO_WEEK(CREATED)
"
"Functions (Time and Date)","YEAR"," "Functions (Time and Date)","YEAR","
YEAR(timestamp) YEAR(timestamp)
"," ","
...@@ -3828,6 +3854,14 @@ Returns the year from a timestamp. ...@@ -3828,6 +3854,14 @@ Returns the year from a timestamp.
YEAR(CREATED) YEAR(CREATED)
" "
"Functions (Time and Date)","ISO_YEAR","
ISO_YEAR(timestamp)
","
Returns the ISO week year from a timestamp.
","
ISO_YEAR(CREATED)
"
"Functions (System)","ARRAY_GET"," "Functions (System)","ARRAY_GET","
ARRAY_GET(arrayExpression, indexExpression) ARRAY_GET(arrayExpression, indexExpression)
"," ","
......
...@@ -10,7 +10,6 @@ import org.h2.engine.DbObject; ...@@ -10,7 +10,6 @@ import org.h2.engine.DbObject;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.ExpressionVisitor; import org.h2.expression.ExpressionVisitor;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.message.DbException;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.schema.Schema; import org.h2.schema.Schema;
......
...@@ -111,14 +111,9 @@ public class Function extends Expression implements FunctionCall { ...@@ -111,14 +111,9 @@ public class Function extends Expression implements FunctionCall {
ISO_WEEK = 124, ISO_DAY_OF_WEEK = 125; ISO_WEEK = 124, ISO_DAY_OF_WEEK = 125;
/** /**
* Pseudo function for {@code EXTRACT(MILLISECOND FROM ...)}. * Pseudo functions for DATEADD, DATEDIFF, and EXTRACT.
*/ */
public static final int MILLISECOND = 126; public static final int MILLISECOND = 126, EPOCH = 127, MICROSECOND = 128, NANOSECOND = 129;
/**
* Pseudo function for {@code EXTRACT(EPOCH FROM ...)}.
*/
public static final int EPOCH = 127;
public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152, public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152,
IDENTITY = 153, SCOPE_IDENTITY = 154, AUTOCOMMIT = 155, IDENTITY = 153, SCOPE_IDENTITY = 154, AUTOCOMMIT = 155,
...@@ -206,6 +201,10 @@ public class Function extends Expression implements FunctionCall { ...@@ -206,6 +201,10 @@ public class Function extends Expression implements FunctionCall {
DATE_PART.put("MILLISECOND", MILLISECOND); DATE_PART.put("MILLISECOND", MILLISECOND);
DATE_PART.put("MS", MILLISECOND); DATE_PART.put("MS", MILLISECOND);
DATE_PART.put("EPOCH", EPOCH); DATE_PART.put("EPOCH", EPOCH);
DATE_PART.put("MICROSECOND", MICROSECOND);
DATE_PART.put("MCS", MICROSECOND);
DATE_PART.put("NANOSECOND", NANOSECOND);
DATE_PART.put("NS", NANOSECOND);
// SOUNDEX_INDEX // SOUNDEX_INDEX
String index = "7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R"; String index = "7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R";
...@@ -864,7 +863,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -864,7 +863,7 @@ public class Function extends Expression implements FunctionCall {
case SECOND: case SECOND:
case WEEK: case WEEK:
case YEAR: case YEAR:
result = ValueInt.get(getDatePart(v0, info.type)); result = ValueInt.get(getIntDatePart(v0, info.type));
break; break;
case MONTH_NAME: { case MONTH_NAME: {
SimpleDateFormat monthName = new SimpleDateFormat("MMMM", SimpleDateFormat monthName = new SimpleDateFormat("MMMM",
...@@ -1502,12 +1501,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -1502,12 +1501,8 @@ public class Function extends Expression implements FunctionCall {
break; break;
case EXTRACT: { case EXTRACT: {
int field = getDatePart(v0.getString()); int field = getDatePart(v0.getString());
// Normal case when we don't retrieve the EPOCH time
if (field != EPOCH) { if (field != EPOCH) {
result = ValueInt.get(getIntDatePart(v1, field));
result = ValueInt.get(getDatePart(v1, field));
} else { } else {
// Case where we retrieve the EPOCH time. // Case where we retrieve the EPOCH time.
...@@ -1530,27 +1525,30 @@ public class Function extends Expression implements FunctionCall { ...@@ -1530,27 +1525,30 @@ public class Function extends Expression implements FunctionCall {
} else if (v1 instanceof ValueDate) { } else if (v1 instanceof ValueDate) {
// Case where the value is of type date '2000:01:01', we have to retrieve the total // Case where the value is of type date '2000:01:01', we have to retrieve the
// number of days and multiply it by the number of seconds in a day. // total number of days and multiply it by the number of seconds in a day.
result = ValueDecimal.get(numberOfDays.multiply(secondsPerDay)); result = ValueDecimal.get(numberOfDays.multiply(secondsPerDay));
} else if (v1 instanceof ValueTimestampTimeZone) { } else if (v1 instanceof ValueTimestampTimeZone) {
// Case where the value is a of type ValueTimestampTimeZone ('2000:01:01 10:00:00+05). // Case where the value is a of type ValueTimestampTimeZone
// We retrieve the time zone offset in minute // ('2000:01:01 10:00:00+05').
// We retrieve the time zone offset in minutes
ValueTimestampTimeZone v = (ValueTimestampTimeZone) v1; ValueTimestampTimeZone v = (ValueTimestampTimeZone) v1;
BigDecimal timeZoneOffsetSeconds = new BigDecimal(v.getTimeZoneOffsetMins() * 60); BigDecimal timeZoneOffsetSeconds = new BigDecimal(v.getTimeZoneOffsetMins() * 60);
// Sum the time in nanoseconds and the total number of days in seconds // Sum the time in nanoseconds and the total number of days in seconds
// and adding the timeZone offset in seconds. // and adding the timeZone offset in seconds.
result = ValueDecimal.get(timeNanosBigDecimal.divide(nanosSeconds) result = ValueDecimal.get(timeNanosBigDecimal.divide(nanosSeconds)
.add(numberOfDays.multiply(secondsPerDay)) .add(numberOfDays.multiply(secondsPerDay)).subtract(timeZoneOffsetSeconds));
.subtract(timeZoneOffsetSeconds));
} else { } else {
// By default, we have the date and the time ('2000:01:01 10:00:00) if no type is given. // By default, we have the date and the time ('2000:01:01 10:00:00') if no type
// We just have to sum the time in nanoseconds and the total number of days in seconds. // is given.
result = ValueDecimal.get(timeNanosBigDecimal.divide(nanosSeconds).add(numberOfDays.multiply(secondsPerDay))); // We just have to sum the time in nanoseconds and the total number of days in
// seconds.
result = ValueDecimal
.get(timeNanosBigDecimal.divide(nanosSeconds).add(numberOfDays.multiply(secondsPerDay)));
} }
} }
break; break;
...@@ -1866,8 +1864,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1866,8 +1864,7 @@ public class Function extends Expression implements FunctionCall {
private static Value dateadd(String part, long count, Value v) { private static Value dateadd(String part, long count, Value v) {
int field = getDatePart(part); int field = getDatePart(part);
//v = v.convertTo(Value.TIMESTAMP); if (field != MILLISECOND && field != MICROSECOND && field != NANOSECOND &&
if (field != MILLISECOND &&
(count > Integer.MAX_VALUE || count < Integer.MIN_VALUE)) { (count > Integer.MAX_VALUE || count < Integer.MIN_VALUE)) {
throw DbException.getInvalidValueException("DATEADD count", count); throw DbException.getInvalidValueException("DATEADD count", count);
} }
...@@ -1917,11 +1914,17 @@ public class Function extends Expression implements FunctionCall { ...@@ -1917,11 +1914,17 @@ public class Function extends Expression implements FunctionCall {
count *= 60_000_000_000L; count *= 60_000_000_000L;
break; break;
case SECOND: case SECOND:
case EPOCH:
count *= 1_000_000_000; count *= 1_000_000_000;
break; break;
case MILLISECOND: case MILLISECOND:
count *= 1_000_000; count *= 1_000_000;
break; break;
case MICROSECOND:
count *= 1_000;
break;
case NANOSECOND:
break;
default: default:
throw DbException.getUnsupportedException("DATEADD " + part); throw DbException.getUnsupportedException("DATEADD " + part);
} }
...@@ -1966,17 +1969,27 @@ public class Function extends Expression implements FunctionCall { ...@@ -1966,17 +1969,27 @@ public class Function extends Expression implements FunctionCall {
long dateValue2 = a2[0]; long dateValue2 = a2[0];
long absolute2 = DateTimeUtils.absoluteDayFromDateValue(dateValue2); long absolute2 = DateTimeUtils.absoluteDayFromDateValue(dateValue2);
switch (field) { switch (field) {
case NANOSECOND:
case MICROSECOND:
case MILLISECOND: case MILLISECOND:
case SECOND: case SECOND:
case EPOCH:
case MINUTE: case MINUTE:
case HOUR: case HOUR:
long timeNanos1 = a1[1]; long timeNanos1 = a1[1];
long timeNanos2 = a2[1]; long timeNanos2 = a2[1];
switch (field) { switch (field) {
case NANOSECOND:
return (absolute2 - absolute1) * DateTimeUtils.NANOS_PER_DAY
+ (timeNanos2 - timeNanos1);
case MICROSECOND:
return (absolute2 - absolute1) * (DateTimeUtils.MILLIS_PER_DAY * 1_000)
+ (timeNanos2 / 1_000 - timeNanos1 / 1_000);
case MILLISECOND: case MILLISECOND:
return (absolute2 - absolute1) * DateTimeUtils.MILLIS_PER_DAY return (absolute2 - absolute1) * DateTimeUtils.MILLIS_PER_DAY
+ (timeNanos2 / 1_000_000 - timeNanos1 / 1_000_000); + (timeNanos2 / 1_000_000 - timeNanos1 / 1_000_000);
case SECOND: case SECOND:
case EPOCH:
return (absolute2 - absolute1) * 86_400 return (absolute2 - absolute1) * 86_400
+ (timeNanos2 / 1_000_000_000 - timeNanos1 / 1_000_000_000); + (timeNanos2 / 1_000_000_000 - timeNanos1 / 1_000_000_000);
case MINUTE: case MINUTE:
...@@ -2859,7 +2872,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -2859,7 +2872,7 @@ public class Function extends Expression implements FunctionCall {
* @param field the field type, see {@link Function} for constants * @param field the field type, see {@link Function} for constants
* @return the value * @return the value
*/ */
public static int getDatePart(Value date, int field) { public static int getIntDatePart(Value date, int field) {
long[] a = DateTimeUtils.dateAndTimeFromValue(date); long[] a = DateTimeUtils.dateAndTimeFromValue(date);
long dateValue = a[0]; long dateValue = a[0];
long timeNanos = a[1]; long timeNanos = a[1];
...@@ -2878,6 +2891,10 @@ public class Function extends Expression implements FunctionCall { ...@@ -2878,6 +2891,10 @@ public class Function extends Expression implements FunctionCall {
return (int) (timeNanos / 1_000_000_000 % 60); return (int) (timeNanos / 1_000_000_000 % 60);
case Function.MILLISECOND: case Function.MILLISECOND:
return (int) (timeNanos / 1_000_000 % 1_000); return (int) (timeNanos / 1_000_000 % 1_000);
case Function.MICROSECOND:
return (int) (timeNanos / 1_000 % 1_000_000);
case Function.NANOSECOND:
return (int) (timeNanos % 1_000_000_000);
case Function.DAY_OF_YEAR: case Function.DAY_OF_YEAR:
return DateTimeUtils.getDayOfYear(dateValue); return DateTimeUtils.getDayOfYear(dateValue);
case Function.DAY_OF_WEEK: case Function.DAY_OF_WEEK:
......
...@@ -171,7 +171,7 @@ public class DataReader extends Reader { ...@@ -171,7 +171,7 @@ public class DataReader extends Reader {
int i = 0; int i = 0;
try { try {
for (; i < len; i++) { for (; i < len; i++) {
buff[i] = readChar(); buff[off + i] = readChar();
} }
return len; return len;
} catch (EOFException e) { } catch (EOFException e) {
......
...@@ -224,7 +224,8 @@ public class ChangeFileEncryption extends Tool { ...@@ -224,7 +224,8 @@ public class ChangeFileEncryption extends Tool {
try (FileChannel fileIn = getFileChannel(fileName, "r", decryptKey)){ try (FileChannel fileIn = getFileChannel(fileName, "r", decryptKey)){
try(InputStream inStream = new FileChannelInputStream(fileIn, true)) { try(InputStream inStream = new FileChannelInputStream(fileIn, true)) {
FileUtils.delete(temp); FileUtils.delete(temp);
try (OutputStream outStream = new FileChannelOutputStream(getFileChannel(temp, "rw", encryptKey), true)) { try (OutputStream outStream = new FileChannelOutputStream(getFileChannel(temp, "rw", encryptKey),
true)) {
byte[] buffer = new byte[4 * 1024]; byte[] buffer = new byte[4 * 1024];
long remaining = fileIn.size(); long remaining = fileIn.size();
long total = remaining; long total = remaining;
......
...@@ -921,19 +921,6 @@ public class DateTimeUtils { ...@@ -921,19 +921,6 @@ public class DateTimeUtils {
return new Date(millis); return new Date(millis);
} }
/**
* Convert an encoded date value to millis, using the supplied timezone.
*
* @param tz the timezone
* @param dateValue the date value
* @return the date
*/
public static long convertDateValueToMillis(TimeZone tz, long dateValue) {
return getMillis(tz, yearFromDateValue(dateValue),
monthFromDateValue(dateValue), dayFromDateValue(dateValue), 0,
0, 0, 0);
}
/** /**
* Convert an encoded date-time value to millis, using the supplied timezone. * Convert an encoded date-time value to millis, using the supplied timezone.
* *
......
...@@ -14,7 +14,6 @@ import java.io.Reader; ...@@ -14,7 +14,6 @@ import java.io.Reader;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.sql.SQLException; import java.sql.SQLException;
...@@ -463,10 +462,6 @@ public class Transfer { ...@@ -463,10 +462,6 @@ public class Transfer {
throw DbException.get( throw DbException.get(
ErrorCode.CONNECTION_BROKEN_1, "length=" + length); ErrorCode.CONNECTION_BROKEN_1, "length=" + length);
} }
if (length > Integer.MAX_VALUE) {
throw DbException.get(
ErrorCode.CONNECTION_BROKEN_1, "length="+ length);
}
writeLong(length); writeLong(length);
Reader reader = v.getReader(); Reader reader = v.getReader();
Data.copyString(reader, out); Data.copyString(reader, out);
...@@ -652,21 +647,10 @@ public class Transfer { ...@@ -652,21 +647,10 @@ public class Transfer {
return ValueLobDb.create( return ValueLobDb.create(
Value.CLOB, session.getDataHandler(), tableId, id, hmac, precision); Value.CLOB, session.getDataHandler(), tableId, id, hmac, precision);
} }
if (length < 0 || length > Integer.MAX_VALUE) { if (length < 0) {
throw DbException.get( throw DbException.get(
ErrorCode.CONNECTION_BROKEN_1, "length="+ length); ErrorCode.CONNECTION_BROKEN_1, "length="+ length);
} }
DataReader reader = new DataReader(in);
int len = (int) length;
char[] buff = new char[len];
IOUtils.readFully(reader, buff, len);
int magic = readInt();
if (magic != LOB_MAGIC) {
throw DbException.get(
ErrorCode.CONNECTION_BROKEN_1, "magic=" + magic);
}
byte[] small = new String(buff).getBytes(StandardCharsets.UTF_8);
return ValueLobDb.createSmallLob(Value.CLOB, small, length);
} }
Value v = session.getDataHandler().getLobStorage(). Value v = session.getDataHandler().getLobStorage().
createClob(new DataReader(in), length); createClob(new DataReader(in), length);
......
...@@ -26,6 +26,7 @@ import org.h2.store.FileStoreInputStream; ...@@ -26,6 +26,7 @@ import org.h2.store.FileStoreInputStream;
import org.h2.store.FileStoreOutputStream; import org.h2.store.FileStoreOutputStream;
import org.h2.store.LobStorageFrontend; import org.h2.store.LobStorageFrontend;
import org.h2.store.LobStorageInterface; import org.h2.store.LobStorageInterface;
import org.h2.store.RangeReader;
import org.h2.store.fs.FileUtils; import org.h2.store.fs.FileUtils;
import org.h2.util.IOUtils; import org.h2.util.IOUtils;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
...@@ -544,6 +545,15 @@ public class ValueLobDb extends Value implements Value.ValueClob, ...@@ -544,6 +545,15 @@ public class ValueLobDb extends Value implements Value.ValueClob,
*/ */
public static ValueLobDb createTempClob(Reader in, long length, public static ValueLobDb createTempClob(Reader in, long length,
DataHandler handler) { DataHandler handler) {
if (length >= 0) {
// Otherwise BufferedReader may try to read more data than needed and that
// blocks the network level
try {
in = new RangeReader(in, 0, length);
} catch (IOException e) {
throw DbException.convert(e);
}
}
BufferedReader reader; BufferedReader reader;
if (in instanceof BufferedReader) { if (in instanceof BufferedReader) {
reader = (BufferedReader) in; reader = (BufferedReader) in;
......
...@@ -219,34 +219,31 @@ public class ValueTimestampTimeZone extends Value { ...@@ -219,34 +219,31 @@ public class ValueTimestampTimeZone extends Value {
@Override @Override
protected int compareSecure(Value o, CompareMode mode) { protected int compareSecure(Value o, CompareMode mode) {
ValueTimestampTimeZone t = (ValueTimestampTimeZone) o; ValueTimestampTimeZone t = (ValueTimestampTimeZone) o;
// We are pretending that the dateValue is in UTC because that gives us // Maximum time zone offset is +/-18 hours so difference in days between local
// a stable sort even if the DST database changes. // and UTC cannot be more than one day
long daysA = DateTimeUtils.absoluteDayFromDateValue(dateValue);
// convert to minutes and add timezone offset long timeA = timeNanos - timeZoneOffsetMins * 60_000_000_000L;
long a = DateTimeUtils.convertDateValueToMillis( if (timeA < 0) {
DateTimeUtils.UTC, dateValue) / timeA += DateTimeUtils.NANOS_PER_DAY;
(1000L * 60L); daysA--;
long ma = timeNanos / (1000L * 1000L * 1000L * 60L); } else if (timeA >= DateTimeUtils.NANOS_PER_DAY) {
a += ma; timeA -= DateTimeUtils.NANOS_PER_DAY;
a -= timeZoneOffsetMins; daysA++;
}
// convert to minutes and add timezone offset long daysB = DateTimeUtils.absoluteDayFromDateValue(t.dateValue);
long b = DateTimeUtils.convertDateValueToMillis( long timeB = t.timeNanos - t.timeZoneOffsetMins * 60_000_000_000L;
DateTimeUtils.UTC, t.dateValue) / if (timeB < 0) {
(1000L * 60L); timeB += DateTimeUtils.NANOS_PER_DAY;
long mb = t.timeNanos / (1000L * 1000L * 1000L * 60L); daysB--;
b += mb; } else if (timeB >= DateTimeUtils.NANOS_PER_DAY) {
b -= t.timeZoneOffsetMins; timeB -= DateTimeUtils.NANOS_PER_DAY;
daysB++;
// compare date }
int c = Long.compare(a, b); int cmp = Long.compare(daysA, daysB);
if (c != 0) { if (cmp != 0) {
return c; return cmp;
} }
// compare time return Long.compare(timeA, timeB);
long na = timeNanos - (ma * 1000L * 1000L * 1000L * 60L);
long nb = t.timeNanos - (mb * 1000L * 1000L * 1000L * 60L);
return Long.compare(na, nb);
} }
@Override @Override
......
...@@ -119,7 +119,20 @@ public class TestLobApi extends TestBase { ...@@ -119,7 +119,20 @@ public class TestLobApi extends TestBase {
prep.setString(1, ""); prep.setString(1, "");
prep.setBytes(2, new byte[0]); prep.setBytes(2, new byte[0]);
prep.execute(); prep.execute();
Random r = new Random(1); Random r = new Random(1);
char[] charsSmall = new char[20];
for (int i = 0; i < charsSmall.length; i++) {
charsSmall[i] = (char) r.nextInt(10000);
}
String dSmall = new String(charsSmall);
prep.setCharacterStream(1, new StringReader(dSmall), -1);
byte[] bytesSmall = new byte[20];
r.nextBytes(bytesSmall);
prep.setBinaryStream(2, new ByteArrayInputStream(bytesSmall), -1);
prep.execute();
char[] chars = new char[100000]; char[] chars = new char[100000];
for (int i = 0; i < chars.length; i++) { for (int i = 0; i < chars.length; i++) {
chars[i] = (char) r.nextInt(10000); chars[i] = (char) r.nextInt(10000);
...@@ -130,6 +143,7 @@ public class TestLobApi extends TestBase { ...@@ -130,6 +143,7 @@ public class TestLobApi extends TestBase {
r.nextBytes(bytes); r.nextBytes(bytes);
prep.setBinaryStream(2, new ByteArrayInputStream(bytes), -1); prep.setBinaryStream(2, new ByteArrayInputStream(bytes), -1);
prep.execute(); prep.execute();
conn.setAutoCommit(false); conn.setAutoCommit(false);
ResultSet rs = stat.executeQuery("select * from test order by id"); ResultSet rs = stat.executeQuery("select * from test order by id");
rs.next(); rs.next();
...@@ -138,18 +152,27 @@ public class TestLobApi extends TestBase { ...@@ -138,18 +152,27 @@ public class TestLobApi extends TestBase {
rs.next(); rs.next();
Clob c2 = rs.getClob(2); Clob c2 = rs.getClob(2);
Blob b2 = rs.getBlob(3); Blob b2 = rs.getBlob(3);
rs.next();
Clob c3 = rs.getClob(2);
Blob b3 = rs.getBlob(3);
assertFalse(rs.next()); assertFalse(rs.next());
// now close // now close
rs.close(); rs.close();
// but the LOBs must stay open // but the LOBs must stay open
assertEquals(0, c1.length()); assertEquals(0, c1.length());
assertEquals(0, b1.length()); assertEquals(0, b1.length());
assertEquals(chars.length, c2.length());
assertEquals(bytes.length, b2.length());
assertEquals("", c1.getSubString(1, 0)); assertEquals("", c1.getSubString(1, 0));
assertEquals(new byte[0], b1.getBytes(1, 0)); assertEquals(new byte[0], b1.getBytes(1, 0));
assertEquals(d, c2.getSubString(1, (int) c2.length()));
assertEquals(bytes, b2.getBytes(1, (int) b2.length())); assertEquals(charsSmall.length, c2.length());
assertEquals(bytesSmall.length, b2.length());
assertEquals(dSmall, c2.getSubString(1, (int) c2.length()));
assertEquals(bytesSmall, b2.getBytes(1, (int) b2.length()));
assertEquals(chars.length, c3.length());
assertEquals(bytes.length, b3.length());
assertEquals(d, c3.getSubString(1, (int) c3.length()));
assertEquals(bytes, b3.getBytes(1, (int) b3.length()));
stat.execute("drop table test"); stat.execute("drop table test");
conn.close(); conn.close();
} }
......
...@@ -105,6 +105,18 @@ call dateadd('MS', 1, TIMESTAMP '2001-02-03 04:05:06.789001'); ...@@ -105,6 +105,18 @@ call dateadd('MS', 1, TIMESTAMP '2001-02-03 04:05:06.789001');
> 2001-02-03 04:05:06.790001 > 2001-02-03 04:05:06.790001
> rows: 1 > rows: 1
SELECT DATEADD('MICROSECOND', 1, TIME '10:00:01'), DATEADD('MCS', 1, TIMESTAMP '2010-10-20 10:00:01.1');
> TIME '10:00:01.000001' TIMESTAMP '2010-10-20 10:00:01.100001'
> ---------------------- --------------------------------------
> 10:00:01.000001 2010-10-20 10:00:01.100001
> rows: 1
SELECT DATEADD('NANOSECOND', 1, TIME '10:00:01'), DATEADD('NS', 1, TIMESTAMP '2010-10-20 10:00:01.1');
> TIME '10:00:01.000000001' TIMESTAMP '2010-10-20 10:00:01.100000001'
> ------------------------- -----------------------------------------
> 10:00:01.000000001 2010-10-20 10:00:01.100000001
> rows: 1
SELECT DATEADD('HOUR', 1, DATE '2010-01-20'); SELECT DATEADD('HOUR', 1, DATE '2010-01-20');
> TIMESTAMP '2010-01-20 01:00:00.0' > TIMESTAMP '2010-01-20 01:00:00.0'
> --------------------------------- > ---------------------------------
......
...@@ -159,6 +159,22 @@ call datediff('MS', TIMESTAMP '1900-01-01 00:00:01.000', TIMESTAMP '2008-01-01 0 ...@@ -159,6 +159,22 @@ call datediff('MS', TIMESTAMP '1900-01-01 00:00:01.000', TIMESTAMP '2008-01-01 0
> 3408134399000 > 3408134399000
> rows: 1 > rows: 1
SELECT DATEDIFF('MICROSECOND', '2006-01-01 00:00:00.0000000', '2006-01-01 00:00:00.123456789'),
DATEDIFF('MCS', '2006-01-01 00:00:00.0000000', '2006-01-01 00:00:00.123456789'),
DATEDIFF('MCS', '2006-01-01 00:00:00.0000000', '2006-01-02 00:00:00.123456789');
> 123456 123456 86400123456
> ------ ------ -----------
> 123456 123456 86400123456
> rows: 1
SELECT DATEDIFF('NANOSECOND', '2006-01-01 00:00:00.0000000', '2006-01-01 00:00:00.123456789'),
DATEDIFF('NS', '2006-01-01 00:00:00.0000000', '2006-01-01 00:00:00.123456789'),
DATEDIFF('NS', '2006-01-01 00:00:00.0000000', '2006-01-02 00:00:00.123456789');
> 123456789 123456789 86400123456789
> --------- --------- --------------
> 123456789 123456789 86400123456789
> rows: 1
SELECT DATEDIFF('WEEK', DATE '2018-02-02', DATE '2018-02-03'), DATEDIFF('ISO_WEEK', DATE '2018-02-02', DATE '2018-02-03'); SELECT DATEDIFF('WEEK', DATE '2018-02-02', DATE '2018-02-03'), DATEDIFF('ISO_WEEK', DATE '2018-02-02', DATE '2018-02-03');
> 0 0 > 0 0
> - - > - -
......
...@@ -3,6 +3,20 @@ ...@@ -3,6 +3,20 @@
-- Initial Developer: H2 Group -- Initial Developer: H2 Group
-- --
SELECT EXTRACT (MICROSECOND FROM TIME '10:00:00.123456789'),
EXTRACT (MCS FROM TIMESTAMP '2015-01-01 11:22:33.987654321');
> 123456 987654
> ------ ------
> 123456 987654
> rows: 1
SELECT EXTRACT (NANOSECOND FROM TIME '10:00:00.123456789'),
EXTRACT (NS FROM TIMESTAMP '2015-01-01 11:22:33.987654321');
> 123456789 987654321
> --------- ---------
> 123456789 987654321
> rows: 1
select EXTRACT (EPOCH from time '00:00:00'); select EXTRACT (EPOCH from time '00:00:00');
> 0 > 0
......
...@@ -5,14 +5,12 @@ ...@@ -5,14 +5,12 @@
*/ */
package org.h2.test.unit; package org.h2.test.unit;
import static org.h2.util.DateTimeUtils.dateValue;
import java.util.Calendar; import java.util.Calendar;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.util.DateTimeUtils; import org.h2.util.DateTimeUtils;
import static org.h2.util.DateTimeUtils.dateValue;
/** /**
* Unit tests for the DateTimeUtils class * Unit tests for the DateTimeUtils class
*/ */
...@@ -44,7 +42,7 @@ public class TestDateTimeUtils extends TestBase { ...@@ -44,7 +42,7 @@ public class TestDateTimeUtils extends TestBase {
} }
/** /**
* Test for {@link DateTimeUtils#getSundayDayOfWeek()} and * Test for {@link DateTimeUtils#getSundayDayOfWeek(long)} and
* {@link DateTimeUtils#getIsoDayOfWeek(long)}. * {@link DateTimeUtils#getIsoDayOfWeek(long)}.
*/ */
private void testDayOfWeek() { private void testDayOfWeek() {
......
...@@ -126,21 +126,27 @@ public class TestTimeStampWithTimeZone extends TestBase { ...@@ -126,21 +126,27 @@ public class TestTimeStampWithTimeZone extends TestBase {
ValueTimestampTimeZone a = ValueTimestampTimeZone.parse("1970-01-01 12:00:00.00+00:15"); 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"); ValueTimestampTimeZone b = ValueTimestampTimeZone.parse("1970-01-01 12:00:01.00+01:15");
int c = a.compareTo(b, null); int c = a.compareTo(b, null);
assertEquals(c, 1); assertEquals(1, c);
c = b.compareTo(a, null);
assertEquals(-1, c);
} }
private void test3() { private void test3() {
ValueTimestampTimeZone a = ValueTimestampTimeZone.parse("1970-01-02 00:00:02.00+01:15"); ValueTimestampTimeZone a = ValueTimestampTimeZone.parse("1970-01-02 00:00:02.00+01:15");
ValueTimestampTimeZone b = ValueTimestampTimeZone.parse("1970-01-01 23:00:01.00+00:15"); ValueTimestampTimeZone b = ValueTimestampTimeZone.parse("1970-01-01 23:00:01.00+00:15");
int c = a.compareTo(b, null); int c = a.compareTo(b, null);
assertEquals(c, 1); assertEquals(1, c);
c = b.compareTo(a, null);
assertEquals(-1, c);
} }
private void test4() { private void test4() {
ValueTimestampTimeZone a = ValueTimestampTimeZone.parse("1970-01-02 00:00:01.00+01:15"); ValueTimestampTimeZone a = ValueTimestampTimeZone.parse("1970-01-02 00:00:01.00+01:15");
ValueTimestampTimeZone b = ValueTimestampTimeZone.parse("1970-01-01 23:00:01.00+00:15"); ValueTimestampTimeZone b = ValueTimestampTimeZone.parse("1970-01-01 23:00:01.00+00:15");
int c = a.compareTo(b, null); int c = a.compareTo(b, null);
assertEquals(c, 0); assertEquals(0, c);
c = b.compareTo(a, null);
assertEquals(0, c);
} }
private void test5() throws SQLException { private void test5() throws SQLException {
......
...@@ -764,5 +764,5 @@ mdy destfile hclf forbids spellchecking selfdestruct expects accident jacocoagen ...@@ -764,5 +764,5 @@ mdy destfile hclf forbids spellchecking selfdestruct expects accident jacocoagen
jacoco xdata invokes sourcefiles classfiles duplication crypto stacktraces prt directions handled overly asm hardcoded jacoco xdata invokes sourcefiles classfiles duplication crypto stacktraces prt directions handled overly asm hardcoded
interpolated thead interpolated thead
die weekdiff osx subprocess dow proleptic die weekdiff osx subprocess dow proleptic microsecond microseconds divisible cmp denormalized suppressed saturated mcs
london
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论