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

Fix possible overflow in scale of timestamps

上级 d4ac543e
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
package org.h2.util; package org.h2.util;
import java.math.BigDecimal;
import java.sql.Date; import java.sql.Date;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
...@@ -19,6 +20,7 @@ import org.h2.engine.Mode; ...@@ -19,6 +20,7 @@ import org.h2.engine.Mode;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueDate; import org.h2.value.ValueDate;
import org.h2.value.ValueDecimal;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
import org.h2.value.ValueTime; import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
...@@ -1448,4 +1450,19 @@ public class DateTimeUtils { ...@@ -1448,4 +1450,19 @@ public class DateTimeUtils {
return b.toString(); return b.toString();
} }
/**
* Converts scale of nanoseconds.
*
* @param nanosOfDay nanoseconds of day
* @param scale fractional seconds precision
* @return scaled value
*/
public static long convertScale(long nanosOfDay, int scale) {
BigDecimal bd = BigDecimal.valueOf(nanosOfDay);
bd = bd.movePointLeft(9);
bd = ValueDecimal.setScale(bd, scale);
bd = bd.movePointRight(9);
return bd.longValue();
}
} }
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
*/ */
package org.h2.value; package org.h2.value;
import java.math.BigDecimal;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp; import java.sql.Timestamp;
...@@ -216,15 +215,16 @@ public class ValueTimestamp extends Value { ...@@ -216,15 +215,16 @@ public class ValueTimestamp extends Value {
throw DbException.getInvalidValueException("scale", targetScale); throw DbException.getInvalidValueException("scale", targetScale);
} }
long n = timeNanos; long n = timeNanos;
BigDecimal bd = BigDecimal.valueOf(n); long n2 = DateTimeUtils.convertScale(n, targetScale);
bd = bd.movePointLeft(9);
bd = ValueDecimal.setScale(bd, targetScale);
bd = bd.movePointRight(9);
long n2 = bd.longValue();
if (n2 == n) { if (n2 == n) {
return this; return this;
} }
return fromDateValueAndNanos(dateValue, n2); long dv = dateValue;
if (n2 >= DateTimeUtils.NANOS_PER_DAY) {
n2 -= DateTimeUtils.NANOS_PER_DAY;
dv = DateTimeUtils.dateValueFromAbsoluteDay(DateTimeUtils.absoluteDayFromDateValue(dateValue) + 1);
}
return fromDateValueAndNanos(dv, n2);
} }
@Override @Override
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
*/ */
package org.h2.value; package org.h2.value;
import java.math.BigDecimal;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp; import java.sql.Timestamp;
...@@ -205,15 +204,16 @@ public class ValueTimestampTimeZone extends Value { ...@@ -205,15 +204,16 @@ public class ValueTimestampTimeZone extends Value {
throw DbException.getInvalidValueException("scale", targetScale); throw DbException.getInvalidValueException("scale", targetScale);
} }
long n = timeNanos; long n = timeNanos;
BigDecimal bd = BigDecimal.valueOf(n); long n2 = DateTimeUtils.convertScale(n, targetScale);
bd = bd.movePointLeft(9);
bd = ValueDecimal.setScale(bd, targetScale);
bd = bd.movePointRight(9);
long n2 = bd.longValue();
if (n2 == n) { if (n2 == n) {
return this; return this;
} }
return fromDateValueAndNanos(dateValue, n2, timeZoneOffsetMins); long dv = dateValue;
if (n2 >= DateTimeUtils.NANOS_PER_DAY) {
n2 -= DateTimeUtils.NANOS_PER_DAY;
dv = DateTimeUtils.dateValueFromAbsoluteDay(DateTimeUtils.absoluteDayFromDateValue(dateValue) + 1);
}
return fromDateValueAndNanos(dv, n2, timeZoneOffsetMins);
} }
@Override @Override
......
...@@ -84,5 +84,16 @@ SELECT T7, T8, T9 FROM TEST; ...@@ -84,5 +84,16 @@ SELECT T7, T8, T9 FROM TEST;
> 2000-01-01 08:00:00.1234568+00 2000-01-01 08:00:00.12345679+00 2000-01-01 08:00:00.123456789+00 > 2000-01-01 08:00:00.1234568+00 2000-01-01 08:00:00.12345679+00 2000-01-01 08:00:00.123456789+00
> rows: 1 > rows: 1
DELETE FROM TEST;
> update count: 1
INSERT INTO TEST(T0) VALUES ('2000-01-01 23:59:59.999999999Z');
> update count: 1
SELECT T0 FROM TEST;
> T0
> ------------------------
> 2000-01-02 00:00:00.0+00
DROP TABLE TEST; DROP TABLE TEST;
> ok > ok
...@@ -77,5 +77,16 @@ SELECT T7, T8, T9 FROM TEST; ...@@ -77,5 +77,16 @@ SELECT T7, T8, T9 FROM TEST;
> 2000-01-01 08:00:00.1234568 2000-01-01 08:00:00.12345679 2000-01-01 08:00:00.123456789 > 2000-01-01 08:00:00.1234568 2000-01-01 08:00:00.12345679 2000-01-01 08:00:00.123456789
> rows: 1 > rows: 1
DELETE FROM TEST;
> update count: 1
INSERT INTO TEST(T0) VALUES ('2000-01-01 23:59:59.999999999');
> update count: 1
SELECT T0 FROM TEST;
> T0
> ---------------------
> 2000-01-02 00:00:00.0
DROP TABLE TEST; DROP TABLE TEST;
> ok > ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论