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

Fix negative intervals with 0 in leading field

上级 e17bac80
......@@ -14,6 +14,8 @@ public final class Interval {
private final IntervalQualifier qualifier;
private final boolean negative;
private final long leading;
private final long remaining;
......@@ -21,16 +23,24 @@ public final class Interval {
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
*/
public Interval(IntervalQualifier qualifier, long leading, long remaining) {
public Interval(IntervalQualifier qualifier, boolean negative, long leading, long remaining) {
if (qualifier == null) {
throw new NullPointerException();
}
if (leading == 0L && remaining == 0L) {
negative = false;
} else if (leading < 0L || remaining < 0L) {
throw new RuntimeException();
}
this.qualifier = qualifier;
this.negative = negative;
this.leading = leading;
this.remaining = remaining;
}
......@@ -44,6 +54,15 @@ public final class Interval {
return qualifier;
}
/**
* Returns where the interval is negative.
*
* @return where the interval is negative
*/
public boolean isNegative() {
return negative;
}
/**
* Returns value of leading field of this interval. For {@code SECOND}
* intervals returns integer part of seconds.
......@@ -69,6 +88,7 @@ public final class Interval {
final int prime = 31;
int result = 1;
result = prime * result + qualifier.hashCode();
result = prime * result + (negative ? 1231 : 1237);
result = prime * result + (int) (leading ^ leading >>> 32);
result = prime * result + (int) (remaining ^ remaining >>> 32);
return result;
......@@ -83,12 +103,13 @@ public final class Interval {
return false;
}
Interval other = (Interval) obj;
return qualifier == other.qualifier && leading == other.leading || remaining == other.remaining;
return qualifier == other.qualifier && negative == other.negative && leading == other.leading
&& remaining == other.remaining;
}
@Override
public String toString() {
return DateTimeUtils.intervalToString(qualifier, leading, remaining);
return DateTimeUtils.intervalToString(qualifier, negative, leading, remaining);
}
}
......@@ -205,13 +205,20 @@ public class IntervalOperation extends Expression {
case DATETIME_MINUS_DATETIME:
if (lType == Value.TIME && rType == Value.TIME) {
long diff = ((ValueTime) l).getNanos() - ((ValueTime) r).getNanos();
return ValueInterval.from(IntervalQualifier.HOUR_TO_SECOND, diff / 3_600_000_000_000L,
Math.abs(diff % 3_600_000_000_000L));
boolean negative = diff < 0;
if (negative) {
diff = -diff;
}
return ValueInterval.from(IntervalQualifier.HOUR_TO_SECOND, negative, diff / 3_600_000_000_000L,
diff % 3_600_000_000_000L);
} else if (lType == Value.DATE && rType == Value.DATE) {
return ValueInterval.from(IntervalQualifier.DAY,
DateTimeUtils.absoluteDayFromDateValue(((ValueDate) l).getDateValue())
- DateTimeUtils.absoluteDayFromDateValue(((ValueDate) r).getDateValue()),
0L);
long diff = DateTimeUtils.absoluteDayFromDateValue(((ValueDate) l).getDateValue())
- DateTimeUtils.absoluteDayFromDateValue(((ValueDate) r).getDateValue());
boolean negative = diff < 0;
if (negative) {
diff = -diff;
}
return ValueInterval.from(IntervalQualifier.DAY, negative, diff, 0L);
} else {
long[] a = DateTimeUtils.dateAndTimeFromValue(l);
long[] b = DateTimeUtils.dateAndTimeFromValue(r);
......
......@@ -3936,7 +3936,7 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
value = value.convertTo(Value.INTERVAL_DAY_TO_SECOND);
}
ValueInterval v = (ValueInterval) value;
return type.cast(new Interval(v.getQualifier(), v.getLeading(), v.getRemaining()));
return type.cast(new Interval(v.getQualifier(), false, v.getLeading(), v.getRemaining()));
} else if (DataType.isGeometryClass(type)) {
return type.cast(value.convertTo(Value.GEOMETRY).getObject());
} else if (type == LocalDateTimeUtils.LOCAL_DATE) {
......
......@@ -448,8 +448,12 @@ public class ValueDataType implements DataType {
case Value.INTERVAL_HOUR:
case Value.INTERVAL_MINUTE: {
ValueInterval interval = (ValueInterval) v;
int ordinal = type - Value.INTERVAL_YEAR;
if (interval.isNegative()) {
ordinal = ~ordinal;
}
buff.put((byte) Value.INTERVAL_YEAR).
put((byte) (type - Value.INTERVAL_YEAR)).
put((byte) (ordinal)).
putVarLong(interval.getLeading());
break;
}
......@@ -462,8 +466,12 @@ public class ValueDataType implements DataType {
case Value.INTERVAL_HOUR_TO_SECOND:
case Value.INTERVAL_MINUTE_TO_SECOND: {
ValueInterval interval = (ValueInterval) v;
int ordinal = type - Value.INTERVAL_YEAR;
if (interval.isNegative()) {
ordinal = ~ordinal;
}
buff.put((byte) Value.INTERVAL_YEAR).
put((byte) (type - Value.INTERVAL_YEAR)).
put((byte) (ordinal)).
putVarLong(interval.getLeading()).
putVarLong(interval.getRemaining());
break;
......@@ -572,8 +580,12 @@ public class ValueDataType implements DataType {
case Value.STRING_FIXED:
return ValueStringFixed.get(readString(buff));
case Value.INTERVAL_YEAR: {
int ordinal = buff.get() & 0xff;
return ValueInterval.from(IntervalQualifier.valueOf(ordinal), readVarLong(buff),
int ordinal = buff.get();
boolean negative = ordinal < 0;
if (negative) {
ordinal = ~ordinal;
}
return ValueInterval.from(IntervalQualifier.valueOf(ordinal), negative, readVarLong(buff),
ordinal < 5 ? 0 : readVarLong(buff));
}
case FLOAT_0_1:
......
......@@ -663,8 +663,12 @@ public class Data {
case Value.INTERVAL_HOUR:
case Value.INTERVAL_MINUTE: {
ValueInterval interval = (ValueInterval) v;
int ordinal = type - Value.INTERVAL_YEAR;
if (interval.isNegative()) {
ordinal = ~ordinal;
}
writeByte((byte) Value.INTERVAL_YEAR);
writeByte((byte) (type - Value.INTERVAL_YEAR));
writeByte((byte) ordinal);
writeVarLong(interval.getLeading());
break;
}
......@@ -677,8 +681,12 @@ public class Data {
case Value.INTERVAL_HOUR_TO_SECOND:
case Value.INTERVAL_MINUTE_TO_SECOND: {
ValueInterval interval = (ValueInterval) v;
int ordinal = type - Value.INTERVAL_YEAR;
if (interval.isNegative()) {
ordinal = ~ordinal;
}
writeByte((byte) Value.INTERVAL_YEAR);
writeByte((byte) (type - Value.INTERVAL_YEAR));
writeByte((byte) ordinal);
writeVarLong(interval.getLeading());
writeVarLong(interval.getRemaining());
break;
......@@ -872,8 +880,12 @@ public class Data {
return ValueResultSet.get(rs);
}
case Value.INTERVAL_YEAR: {
int ordinal = readByte() & 0xff;
return ValueInterval.from(IntervalQualifier.valueOf(ordinal), readVarLong(),
int ordinal = readByte();
boolean negative = ordinal < 0;
if (negative) {
ordinal = ~ordinal;
}
return ValueInterval.from(IntervalQualifier.valueOf(ordinal), negative, readVarLong(),
ordinal < 5 ? 0 : readVarLong());
}
case CUSTOM_DATA_TYPE: {
......
......@@ -1744,12 +1744,20 @@ public class DateTimeUtils {
leading = parseIntervalLeading(s, 0, dash, negative);
remaining = parseIntervalRemainingSeconds(s, dash + 1);
}
return ValueInterval.from(qualifier, leading, remaining);
break;
}
default:
throw new IllegalArgumentException();
}
return ValueInterval.from(qualifier, leading, remaining);
negative = leading < 0;
if (negative) {
if (leading != Long.MIN_VALUE) {
leading = -leading;
} else {
leading = 0;
}
}
return ValueInterval.from(qualifier, negative, leading, remaining);
}
static ValueInterval parseInterval2(IntervalQualifier qualifier, String s, char ch, int max, boolean negative) {
......@@ -1763,11 +1771,22 @@ public class DateTimeUtils {
leading = parseIntervalLeading(s, 0, dash, negative);
remaining = parseIntervalRemaining(s, dash + 1, s.length(), max);
}
return ValueInterval.from(qualifier, leading, remaining);
negative = leading < 0;
if (negative) {
if (leading != Long.MIN_VALUE) {
leading = -leading;
} else {
leading = 0;
}
}
return ValueInterval.from(qualifier, negative, leading, remaining);
}
private static long parseIntervalLeading(String s, int start, int end, boolean negative) {
long leading = Long.parseLong(s.substring(start, end));
if (leading == 0) {
return negative ^ s.charAt(start) == '-' ? Long.MIN_VALUE : 0;
}
return negative ? -leading : leading;
}
......@@ -1799,16 +1818,14 @@ public class DateTimeUtils {
* Formats interval as a string.
*
* @param qualifier qualifier of the interval
* @param negative whether interval is negative
* @param leading the value of leading field
* @param remaining the value of all remaining fields
* @return string representation of the specified interval
*/
public static String intervalToString(IntervalQualifier qualifier, long leading, long remaining) {
public static String intervalToString(IntervalQualifier qualifier, boolean negative, long leading, long remaining)
{
StringBuilder buff = new StringBuilder().append("INTERVAL ");
boolean negative = leading < 0;
if (negative) {
leading = -leading;
}
buff.append('\'');
if (negative) {
buff.append('-');
......@@ -1908,36 +1925,51 @@ public class DateTimeUtils {
* in nanoseconds for day-time intervals
*/
public static BigInteger intervalToAbsolute(ValueInterval interval) {
BigInteger r;
switch (interval.getQualifier()) {
case YEAR:
return BigInteger.valueOf(interval.getLeading()).multiply(BigInteger.valueOf(12));
r = BigInteger.valueOf(interval.getLeading()).multiply(BigInteger.valueOf(12));
break;
case MONTH:
return BigInteger.valueOf(interval.getLeading());
r = BigInteger.valueOf(interval.getLeading());
break;
case DAY:
return BigInteger.valueOf(interval.getLeading()).multiply(BigInteger.valueOf(NANOS_PER_DAY));
r = BigInteger.valueOf(interval.getLeading()).multiply(BigInteger.valueOf(NANOS_PER_DAY));
break;
case HOUR:
return BigInteger.valueOf(interval.getLeading()).multiply(BigInteger.valueOf(3_600_000_000_000L));
r = BigInteger.valueOf(interval.getLeading()).multiply(BigInteger.valueOf(3_600_000_000_000L));
break;
case MINUTE:
return BigInteger.valueOf(interval.getLeading()).multiply(BigInteger.valueOf(60_000_000_000L));
r = BigInteger.valueOf(interval.getLeading()).multiply(BigInteger.valueOf(60_000_000_000L));
break;
case SECOND:
return intervalToAbsolute(interval, 1_000_000_000);
r = intervalToAbsolute(interval, 1_000_000_000);
break;
case YEAR_TO_MONTH:
return intervalToAbsolute(interval, 12);
r = intervalToAbsolute(interval, 12);
break;
case DAY_TO_HOUR:
return intervalToAbsolute(interval, 24, 3_600_000_000_000L);
r = intervalToAbsolute(interval, 24, 3_600_000_000_000L);
break;
case DAY_TO_MINUTE:
return intervalToAbsolute(interval, 24 * 60, 60_000_000_000L);
r = intervalToAbsolute(interval, 24 * 60, 60_000_000_000L);
break;
case DAY_TO_SECOND:
return intervalToAbsolute(interval, NANOS_PER_DAY);
r = intervalToAbsolute(interval, NANOS_PER_DAY);
break;
case HOUR_TO_MINUTE:
return intervalToAbsolute(interval, 60, 60_000_000_000L);
r = intervalToAbsolute(interval, 60, 60_000_000_000L);
break;
case HOUR_TO_SECOND:
return intervalToAbsolute(interval, 3_600_000_000_000L);
r = intervalToAbsolute(interval, 3_600_000_000_000L);
break;
case MINUTE_TO_SECOND:
return intervalToAbsolute(interval, 60_000_000_000L);
r = intervalToAbsolute(interval, 60_000_000_000L);
break;
default:
throw new IllegalArgumentException();
}
return interval.isNegative() ? r.negate() : r;
}
private static BigInteger intervalToAbsolute(ValueInterval interval, long multiplier, long totalMultiplier) {
......@@ -1945,11 +1977,8 @@ public class DateTimeUtils {
}
private static BigInteger intervalToAbsolute(ValueInterval interval, long multiplier) {
long leading = interval.getLeading(), remaining = interval.getRemaining();
if (leading < 0) {
remaining = -remaining;
}
return BigInteger.valueOf(leading).multiply(BigInteger.valueOf(multiplier)).add(BigInteger.valueOf(remaining));
return BigInteger.valueOf(interval.getLeading()).multiply(BigInteger.valueOf(multiplier))
.add(BigInteger.valueOf(interval.getRemaining()));
}
/**
......@@ -1963,17 +1992,19 @@ public class DateTimeUtils {
public static ValueInterval intervalFromAbsolute(IntervalQualifier qualifier, BigInteger absolute) {
switch (qualifier) {
case YEAR:
return ValueInterval.from(qualifier, absolute.divide(BigInteger.valueOf(12)).longValue(), 0);
return ValueInterval.from(qualifier, absolute.signum() < 0,
Math.abs(absolute.divide(BigInteger.valueOf(12)).longValue()), 0);
case MONTH:
return ValueInterval.from(qualifier, leadingExact(absolute), 0);
return ValueInterval.from(qualifier, absolute.signum() < 0, leadingExact(absolute), 0);
case DAY:
return ValueInterval.from(qualifier, leadingExact(absolute.divide(BigInteger.valueOf(NANOS_PER_DAY))), 0);
return ValueInterval.from(qualifier, absolute.signum() < 0,
leadingExact(absolute.divide(BigInteger.valueOf(NANOS_PER_DAY))), 0);
case HOUR:
return ValueInterval.from(qualifier, leadingExact(absolute.divide(BigInteger.valueOf(3_600_000_000_000L))),
0);
return ValueInterval.from(qualifier, absolute.signum() < 0,
leadingExact(absolute.divide(BigInteger.valueOf(3_600_000_000_000L))), 0);
case MINUTE:
return ValueInterval.from(qualifier, leadingExact(absolute.divide(BigInteger.valueOf(60_000_000_000L))),
0);
return ValueInterval.from(qualifier, absolute.signum() < 0,
leadingExact(absolute.divide(BigInteger.valueOf(60_000_000_000L))), 0);
case SECOND:
return intervalFromAbsolute(qualifier, absolute, 1_000_000_000);
case YEAR_TO_MONTH:
......@@ -1997,7 +2028,7 @@ public class DateTimeUtils {
private static ValueInterval intervalFromAbsolute(IntervalQualifier qualifier, BigInteger absolute, long divisor) {
BigInteger[] dr = absolute.divideAndRemainder(BigInteger.valueOf(divisor));
return ValueInterval.from(qualifier, leadingExact(dr[0]), Math.abs(dr[1].longValue()));
return ValueInterval.from(qualifier, absolute.signum() < 0, leadingExact(dr[0]), Math.abs(dr[1].longValue()));
}
private static long leadingExact(BigInteger absolute) {
......@@ -2005,7 +2036,7 @@ public class DateTimeUtils {
|| absolute.compareTo(BigInteger.valueOf(-999_999_999_999_999_999L)) < 0) {
throw DbException.get(ErrorCode.NUMERIC_VALUE_OUT_OF_RANGE_1, absolute.toString());
}
return absolute.longValue();
return Math.abs(absolute.longValue());
}
}
......@@ -562,11 +562,13 @@ public class LocalDateTimeUtils {
try {
long seconds = (long) DURATION_GET_SECONDS.invoke(duration);
int nano = (int) DURATION_GET_NANO.invoke(duration);
if (seconds < 0 && nano != 0) {
boolean negative = seconds < 0;
seconds = Math.abs(seconds);
if (negative && nano != 0) {
nano = 1_000_000_000 - nano;
seconds++;
seconds--;
}
return ValueInterval.from(IntervalQualifier.SECOND, seconds, nano);
return ValueInterval.from(IntervalQualifier.SECOND, negative, seconds, nano);
} catch (IllegalAccessException e) {
throw DbException.convert(e);
} catch (InvocationTargetException e) {
......
......@@ -793,7 +793,8 @@ public class DataType {
return ValueNull.INSTANCE;
}
Interval interval = (Interval) x;
return ValueInterval.from(interval.getQualifier(), interval.getLeading(), interval.getRemaining());
return ValueInterval.from(interval.getQualifier(), interval.isNegative(),
interval.getLeading(), interval.getRemaining());
}
default:
if (JdbcUtils.customDataTypesHandler != null) {
......@@ -1274,7 +1275,7 @@ public class DataType {
return ValueTimestampTimeZone.get((TimestampWithTimeZone) x);
} else if (x instanceof Interval) {
Interval i = (Interval) x;
return ValueInterval.from(i.getQualifier(), i.getLeading(), i.getRemaining());
return ValueInterval.from(i.getQualifier(), i.isNegative(), i.getLeading(), i.getRemaining());
} else if (clazz == LocalDateTimeUtils.DURATION) {
return LocalDateTimeUtils.durationToValue(x);
} else {
......
......@@ -520,9 +520,12 @@ public class Transfer {
case Value.INTERVAL_MONTH:
case Value.INTERVAL_DAY:
case Value.INTERVAL_HOUR:
case Value.INTERVAL_MINUTE:
writeLong(((ValueInterval) v).getLeading());
case Value.INTERVAL_MINUTE: {
ValueInterval interval = (ValueInterval) v;
writeBoolean(interval.isNegative());
writeLong(interval.getLeading());
break;
}
case Value.INTERVAL_SECOND:
case Value.INTERVAL_YEAR_TO_MONTH:
case Value.INTERVAL_DAY_TO_HOUR:
......@@ -532,6 +535,7 @@ public class Transfer {
case Value.INTERVAL_HOUR_TO_SECOND:
case Value.INTERVAL_MINUTE_TO_SECOND: {
ValueInterval interval = (ValueInterval) v;
writeBoolean(interval.isNegative());
writeLong(interval.getLeading());
writeLong(interval.getRemaining());
break;
......@@ -708,7 +712,7 @@ public class Transfer {
case Value.INTERVAL_DAY:
case Value.INTERVAL_HOUR:
case Value.INTERVAL_MINUTE:
return ValueInterval.from(IntervalQualifier.valueOf(type - Value.INTERVAL_YEAR), readLong(), 0L);
return ValueInterval.from(IntervalQualifier.valueOf(type - Value.INTERVAL_YEAR), readBoolean(), readLong(), 0L);
case Value.INTERVAL_SECOND:
case Value.INTERVAL_YEAR_TO_MONTH:
case Value.INTERVAL_DAY_TO_HOUR:
......@@ -717,7 +721,7 @@ public class Transfer {
case Value.INTERVAL_HOUR_TO_MINUTE:
case Value.INTERVAL_HOUR_TO_SECOND:
case Value.INTERVAL_MINUTE_TO_SECOND:
return ValueInterval.from(IntervalQualifier.valueOf(type - Value.INTERVAL_YEAR), readLong(), readLong());
return ValueInterval.from(IntervalQualifier.valueOf(type - Value.INTERVAL_YEAR), readBoolean(), readLong(), readLong());
default:
if (JdbcUtils.customDataTypesHandler != null) {
return JdbcUtils.customDataTypesHandler.convert(
......
......@@ -35,6 +35,8 @@ public class ValueInterval extends Value {
private final int type;
private final boolean negative;
private final long leading;
private final long remaining;
......@@ -42,18 +44,27 @@ public class ValueInterval extends Value {
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return interval value
*/
public static ValueInterval from(IntervalQualifier qualifier, long leading, long remaining) {
return (ValueInterval) Value.cache(new ValueInterval(qualifier.ordinal() + INTERVAL_YEAR, leading, remaining));
public static ValueInterval from(IntervalQualifier qualifier, boolean negative, long leading, long remaining) {
if (leading == 0L && remaining == 0L) {
negative = false;
} else if (leading < 0L || remaining < 0L) {
throw new RuntimeException();
}
return (ValueInterval) Value.cache(
new ValueInterval(qualifier.ordinal() + INTERVAL_YEAR, negative, leading, remaining));
}
private ValueInterval(int type, long leading, long remaining) {
private ValueInterval(int type, boolean negative, long leading, long remaining) {
this.type = type;
this.negative = negative;
this.leading = leading;
this.remaining = remaining;
}
......@@ -99,10 +110,6 @@ public class ValueInterval extends Value {
return this;
}
long l = leading;
boolean negative = l < 0;
if (negative) {
l = -l;
}
switch (type) {
case Value.INTERVAL_SECOND:
if (r >= 1_000_000_000) {
......@@ -129,7 +136,7 @@ public class ValueInterval extends Value {
}
break;
}
return from(qualifier, negative ? -l : l, r);
return from(qualifier, negative, l, r);
}
@Override
......@@ -140,12 +147,12 @@ public class ValueInterval extends Value {
@Override
public String getString() {
return DateTimeUtils.intervalToString(getQualifier(), leading, remaining);
return DateTimeUtils.intervalToString(getQualifier(), negative, leading, remaining);
}
@Override
public Object getObject() {
return new Interval(getQualifier(), leading, remaining);
return new Interval(getQualifier(), negative, leading, remaining);
}
/**
......@@ -157,6 +164,15 @@ public class ValueInterval extends Value {
return IntervalQualifier.valueOf(type - INTERVAL_YEAR);
}
/**
* Returns where the interval is negative.
*
* @return where the interval is negative
*/
public boolean isNegative() {
return negative;
}
/**
* Returns value of leading field of this interval. For {@code SECOND}
* intervals returns integer part of seconds.
......@@ -187,6 +203,7 @@ public class ValueInterval extends Value {
final int prime = 31;
int result = 1;
result = prime * result + type;
result = prime * result + (negative ? 1231 : 1237);
result = prime * result + (int) (leading ^ leading >>> 32);
result = prime * result + (int) (remaining ^ remaining >>> 32);
return result;
......@@ -201,7 +218,8 @@ public class ValueInterval extends Value {
return false;
}
ValueInterval other = (ValueInterval) obj;
return type == other.type && leading == other.leading && remaining == other.remaining;
return type == other.type && negative == other.negative && leading == other.leading
&& remaining == other.remaining;
}
@Override
......@@ -216,7 +234,10 @@ public class ValueInterval extends Value {
@Override
public Value negate() {
return from(getQualifier(), -leading, remaining);
if (leading == 0L && remaining == 0L) {
return this;
}
return from(getQualifier(), !negative, -leading, remaining);
}
}
......@@ -908,7 +908,7 @@ public class TestPreparedStatement extends TestDb {
private void testInterval(Connection conn) throws SQLException {
PreparedStatement prep = conn.prepareStatement("SELECT ?");
Interval interval = new Interval(IntervalQualifier.MINUTE, 100, 0);
Interval interval = new Interval(IntervalQualifier.MINUTE, false, 100, 0);
prep.setObject(1, interval);
ResultSet rs = prep.executeQuery();
rs.next();
......
......@@ -1573,7 +1573,7 @@ public class TestResultSet extends TestDb {
rs = stat.executeQuery("CALL INTERVAL '10' YEAR");
rs.next();
assertEquals("INTERVAL '10' YEAR", rs.getString(1));
Interval expected = new Interval(IntervalQualifier.YEAR, 10, 0);
Interval expected = new Interval(IntervalQualifier.YEAR, false, 10, 0);
assertEquals(expected, rs.getObject(1));
assertEquals(expected, rs.getObject(1, Interval.class));
ResultSetMetaData metaData = rs.getMetaData();
......
......@@ -575,6 +575,15 @@ SELECT CAST(' interval + ''12-2'' Year To Month ' AS INTERVAL YEAR TO MO
SELECT CAST('INTERVAL''11:12''HOUR TO MINUTE' AS INTERVAL HOUR TO MINUTE);
>> INTERVAL '11:12' HOUR TO MINUTE
SELECT INTERVAL '-0-1' YEAR TO MONTH;
>> INTERVAL '-0-1' YEAR TO MONTH
SELECT INTERVAL '-0.1' SECOND;
>> INTERVAL '-0.1' SECOND
SELECT INTERVAL -'0.1' SECOND;
>> INTERVAL '-0.1' SECOND
-- Arithmetic
SELECT INTERVAL '1000' SECOND + INTERVAL '10' MINUTE;
......@@ -673,7 +682,7 @@ SELECT TIMESTAMP WITH TIME ZONE '2000-01-01 12:00:00+01' - INTERVAL '1-2' YEAR T
-- Date-time subtraction
SELECT TIME '10:30:15.123456789' - TIME '11:00:00';
>> INTERVAL '0:29:44.876543211' HOUR TO SECOND
>> INTERVAL '-0:29:44.876543211' HOUR TO SECOND
SELECT DATE '2010-01-15' - DATE '2009-12-31';
>> INTERVAL '15' DAY
......
......@@ -250,13 +250,13 @@ public class TestDateTimeUtils extends TestBase {
}
private void testParseInterval(IntervalQualifier qualifier, long leading, long remaining, String s, String full) {
testParseIntervalImpl(qualifier, leading, remaining, false, s, full);
testParseIntervalImpl(qualifier, -leading, remaining, true, s, full);
testParseIntervalImpl(qualifier, false, leading, remaining, s, full);
testParseIntervalImpl(qualifier, true, leading, remaining, s, full);
}
private void testParseIntervalImpl(IntervalQualifier qualifier, long leading, long remaining, boolean negative,
private void testParseIntervalImpl(IntervalQualifier qualifier, boolean negative, long leading, long remaining,
String s, String full) {
ValueInterval expected = ValueInterval.from(qualifier, leading, remaining);
ValueInterval expected = ValueInterval.from(qualifier, negative, leading, remaining);
assertEquals(expected, DateTimeUtils.parseInterval(qualifier, negative, s));
StringBuilder b = new StringBuilder();
b.append("INTERVAL ").append('\'');
......
......@@ -236,7 +236,7 @@ public class TestValueMemory extends TestBase implements DataHandler {
case Value.INTERVAL_HOUR:
case Value.INTERVAL_MINUTE:
return ValueInterval.from(IntervalQualifier.valueOf(type - Value.INTERVAL_YEAR),
random.nextInt(), 0);
random.nextBoolean(), random.nextInt(Integer.MAX_VALUE), 0);
case Value.INTERVAL_SECOND:
case Value.INTERVAL_YEAR_TO_MONTH:
case Value.INTERVAL_DAY_TO_HOUR:
......@@ -246,7 +246,7 @@ public class TestValueMemory extends TestBase implements DataHandler {
case Value.INTERVAL_HOUR_TO_SECOND:
case Value.INTERVAL_MINUTE_TO_SECOND:
return ValueInterval.from(IntervalQualifier.valueOf(type - Value.INTERVAL_YEAR),
random.nextInt(), random.nextInt(24));
random.nextBoolean(), random.nextInt(Integer.MAX_VALUE), random.nextInt(24));
default:
throw new AssertionError("type=" + type);
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论