Unverified 提交 4a8faf7b authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #813 from katzyn/TIME

Limit range of TIME values by default
......@@ -364,6 +364,39 @@ public class SysProperties {
public static final boolean BIG_DECIMAL_IS_DECIMAL =
Utils.getProperty("h2.bigDecimalIsDecimal", true);
/**
* System property {@code h2.unlimitedTimeRange}, {@code false} by default.
*
* <p>
* Controls limits of TIME data type.
* </p>
*
* <table>
* <thead>
* <tr>
* <th>h2.unlimitedTimeRange</th>
* <th>Minimum TIME value</th>
* <th>Maximum TIME value</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td>false</td>
* <td>00:00:00.000000000</td>
* <td>23:59:59.999999999</td>
* </tr>
* <tr>
* <td>true</td>
* <td>-2562047:47:16.854775808</td>
* <td>2562047:47:16.854775807</td>
* </tr>
* </tbody>
* </table>
*/
public static final boolean UNLIMITED_TIME_RANGE =
Utils.getProperty("h2.unlimitedTimeRange", false);
/**
* System property <code>h2.pgClientEncoding</code> (default: UTF-8).<br />
* Default client encoding for PG server. It is used if the client does not
......
......@@ -403,8 +403,11 @@ public class DateTimeUtils {
}
boolean negative;
hour = Integer.parseInt(s.substring(start, s1));
if (hour < 0) {
if (hour < 0 || hour == 0 && s.charAt(0) == '-') {
if (timeOfDay) {
/*
* This also forbids -00:00:00 and similar values.
*/
throw new IllegalArgumentException(s);
}
negative = true;
......
......@@ -9,6 +9,7 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Time;
import org.h2.api.ErrorCode;
import org.h2.engine.SysProperties;
import org.h2.message.DbException;
import org.h2.util.DateTimeUtils;
import org.h2.util.StringUtils;
......@@ -48,6 +49,14 @@ public class ValueTime extends Value {
* @return the value
*/
public static ValueTime fromNanos(long nanos) {
if (!SysProperties.UNLIMITED_TIME_RANGE) {
if (nanos < 0L || nanos >= 86400000000000L) {
StringBuilder builder = new StringBuilder();
appendTime(builder, nanos, false);
throw DbException.get(ErrorCode.INVALID_DATETIME_CONSTANT_2,
"TIME", builder.toString());
}
}
return (ValueTime) Value.cache(new ValueTime(nanos));
}
......@@ -200,7 +209,13 @@ public class ValueTime extends Value {
buff.append('-');
nanos = -nanos;
}
long ms = nanos / 1000000;
/*
* nanos now either in range from 0 to Long.MAX_VALUE or equals to
* Long.MIN_VALUE. We need to divide nanos by 1000000 with unsigned division to
* get correct result. The simplest way to do this with such constraints is to
* divide -nanos by -1000000.
*/
long ms = -nanos / -1000000;
nanos -= ms * 1000000;
long s = ms / 1000;
ms -= s * 1000;
......
......@@ -14,6 +14,8 @@ import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.h2.api.ErrorCode;
import org.h2.engine.SysProperties;
import org.h2.message.DbException;
import org.h2.test.TestBase;
import org.h2.test.utils.AssertThrows;
import org.h2.util.DateTimeUtils;
......@@ -116,30 +118,48 @@ public class TestDate extends TestBase {
assertEquals("10:20:30", ValueTime.get(Time.valueOf("10:20:30")).getString());
assertEquals("00:00:00", ValueTime.fromNanos(0).getString());
assertEquals("23:59:59", ValueTime.parse("23:59:59").getString());
assertEquals("99:59:59", ValueTime.parse("99:59:59").getString());
assertEquals("-99:02:03.001002003",
ValueTime.parse("-99:02:03.001002003").getString());
assertEquals("-99:02:03.001002",
ValueTime.parse("-99:02:03.001002000").getString());
assertEquals("-99:02:03",
ValueTime.parse("-99:02:03.0000000000001").getString());
assertEquals("1999999:59:59.999999999",
ValueTime.parse("1999999:59:59.999999999").getString());
assertEquals("-1999999:59:59.999999999",
ValueTime.parse("-1999999:59:59.999999999").getString());
assertEquals("11:22:33.444555666", ValueTime.parse("11:22:33.444555666").getString());
if (SysProperties.UNLIMITED_TIME_RANGE) {
assertEquals("99:59:59", ValueTime.parse("99:59:59").getString());
assertEquals("-00:10:10", ValueTime.parse("-00:10:10").getString());
assertEquals("-99:02:03.001002003",
ValueTime.parse("-99:02:03.001002003").getString());
assertEquals("-99:02:03.001002",
ValueTime.parse("-99:02:03.001002000").getString());
assertEquals("-99:02:03",
ValueTime.parse("-99:02:03.0000000000001").getString());
assertEquals("1999999:59:59.999999999",
ValueTime.parse("1999999:59:59.999999999").getString());
assertEquals("-1999999:59:59.999999999",
ValueTime.parse("-1999999:59:59.999999999").getString());
assertEquals("2562047:47:16.854775807",
ValueTime.fromNanos(Long.MAX_VALUE).getString());
assertEquals("-2562047:47:16.854775808",
ValueTime.fromNanos(Long.MIN_VALUE).getString());
} else {
try {
ValueTime.parse("-00:00:00.000000001");
fail();
} catch (DbException ex) {
assertEquals(ErrorCode.INVALID_DATETIME_CONSTANT_2, ex.getErrorCode());
}
try {
ValueTime.parse("24:00:00");
fail();
} catch (DbException ex) {
assertEquals(ErrorCode.INVALID_DATETIME_CONSTANT_2, ex.getErrorCode());
}
}
ValueTime t1 = ValueTime.parse("11:11:11");
assertEquals("11:11:11", t1.getTime().toString());
assertEquals("1970-01-01", t1.getDate().toString());
assertEquals("TIME '11:11:11'", t1.getSQL());
assertEquals("TIME '11:11:11'", t1.toString());
assertEquals(1, t1.getSignum());
assertEquals(-1, t1.negate().getSignum());
assertEquals(0, t1.multiply(ValueInt.get(0)).getSignum());
assertEquals(0, t1.subtract(t1).getSignum());
assertEquals("05:35:35.5", t1.multiply(ValueDouble.get(0.5)).getString());
assertEquals("22:22:22", t1.divide(ValueDouble.get(0.5)).getString());
assertEquals("-11:11:11", t1.negate().getString());
assertEquals("11:11:11", t1.negate().negate().getString());
assertEquals(Value.TIME, t1.getType());
long nanos = t1.getNanos();
assertEquals((int) ((nanos >>> 32) ^ nanos), t1.hashCode());
......@@ -159,20 +179,26 @@ public class TestDate extends TestBase {
ValueTime t2 = ValueTime.parse("22:22:22");
assertFalse(t1.equals(t2));
assertFalse(t2.equals(t1));
assertEquals("33:33:33", t1.add(t2).getString());
assertEquals("33:33:33", t1.multiply(ValueInt.get(4)).subtract(t1).getString());
assertEquals(-1, t1.compareTo(t2, null));
assertEquals(1, t2.compareTo(t1, null));
// can't convert using java.util.Date
assertEquals(
"1969-12-31 23:00:00.0",
ValueTime.parse("-1:00:00").
convertTo(Value.TIMESTAMP).getString());
assertEquals(
"1970-01-01",
ValueTime.parse("-1:00:00").
convertTo(Value.DATE).getString());
if (SysProperties.UNLIMITED_TIME_RANGE) {
assertEquals(-1, t1.negate().getSignum());
assertEquals("-11:11:11", t1.negate().getString());
assertEquals("11:11:11", t1.negate().negate().getString());
assertEquals("33:33:33", t1.add(t2).getString());
assertEquals("33:33:33", t1.multiply(ValueInt.get(4)).subtract(t1).getString());
// can't convert using java.util.Date
assertEquals(
"1969-12-31 23:00:00.0",
ValueTime.parse("-1:00:00").
convertTo(Value.TIMESTAMP).getString());
assertEquals(
"1970-01-01",
ValueTime.parse("-1:00:00").
convertTo(Value.DATE).getString());
}
}
private void testValueTimestampWithTimezone() {
......@@ -285,15 +311,9 @@ public class TestDate extends TestBase {
assertEquals("2001-01-01 01:01:01.0",
ValueTimestamp.parse("2001-01-01").add(
ValueTime.parse("01:01:01")).getString());
assertEquals("2001-01-02 01:01:01.0",
ValueTimestamp.parse("2001-01-01").add(
ValueTime.parse("25:01:01")).getString());
assertEquals("1010-10-10 00:00:00.0",
ValueTimestamp.parse("1010-10-10 10:10:10").subtract(
ValueTime.parse("10:10:10")).getString());
assertEquals("1010-10-10 10:00:00.0",
ValueTimestamp.parse("1010-10-11 10:10:10").subtract(
ValueTime.parse("24:10:10")).getString());
assertEquals("-2001-01-01 01:01:01.0",
ValueTimestamp.parse("-2001-01-01").add(
ValueTime.parse("01:01:01")).getString());
......@@ -301,6 +321,15 @@ public class TestDate extends TestBase {
ValueTimestamp.parse("-1010-10-10 10:10:10").subtract(
ValueTime.parse("10:10:10")).getString());
if (SysProperties.UNLIMITED_TIME_RANGE) {
assertEquals("2001-01-02 01:01:01.0",
ValueTimestamp.parse("2001-01-01").add(
ValueTime.parse("25:01:01")).getString());
assertEquals("1010-10-10 10:00:00.0",
ValueTimestamp.parse("1010-10-11 10:10:10").subtract(
ValueTime.parse("24:10:10")).getString());
}
assertEquals(0, DateTimeUtils.absoluteDayFromDateValue(
ValueTimestamp.parse("1970-01-01").getDateValue()));
assertEquals(0, ValueTimestamp.parse(
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论