提交 8273fd69 authored 作者: Thomas Mueller Graf's avatar Thomas Mueller Graf

An ArrayIndexOutOfBoundsException was thrown in some cases when opening an old version 1.3 database

上级 03eba50f
......@@ -20,7 +20,14 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>-</li>
<ul>
<li>An ArrayIndexOutOfBoundsException was thrown in some cases
when opening an old version 1.3 database, or an 1.4 database with
both "mv_store=false" and the system property "h2.storeLocalTime" set to false.
It mainly showed up with an index on a time, date, or timestamp column.
The system property "h2.storeLocalTime" is no longer supported
(MVStore databases always store local time, and PageStore now databases never do).
</li>
</ul>
<h2>Version 1.4.188 Beta (2015-08-01)</h2>
......
......@@ -423,16 +423,6 @@ public class SysProperties {
public static final long SPLIT_FILE_SIZE_SHIFT =
Utils.getProperty("h2.splitFileSizeShift", 30);
/**
* System property <code>h2.storeLocalTime</code>
* (default: false for version 1.3, true for version 1.4).<br />
* Store the local time. If disabled, the daylight saving offset is not
* taken into account.
*/
public static final boolean STORE_LOCAL_TIME =
Utils.getProperty("h2.storeLocalTime",
Constants.VERSION_MINOR >= 4 ? true : false);
/**
* System property <code>h2.syncMethod</code> (default: sync).<br />
* What method to call when closing the database, on checkpoint, and on
......
......@@ -90,6 +90,15 @@ public class Data {
private static final long MILLIS_PER_MINUTE = 1000 * 60;
/**
* Can not store the local time, because doing so with old database files
* that didn't do it could result in an ArrayIndexOutOfBoundsException. The
* reason is that adding a row to a page only allocated space for the new
* row, but didn't take into account that existing rows now can use more
* space, due to the changed format.
*/
private static final boolean STORE_LOCAL_TIME = false;
/**
* The data itself.
*/
......@@ -485,7 +494,7 @@ public class Data {
break;
}
case Value.TIME:
if (SysProperties.STORE_LOCAL_TIME) {
if (STORE_LOCAL_TIME) {
writeByte((byte) LOCAL_TIME);
ValueTime t = (ValueTime) v;
long nanos = t.getNanos();
......@@ -499,7 +508,7 @@ public class Data {
}
break;
case Value.DATE: {
if (SysProperties.STORE_LOCAL_TIME) {
if (STORE_LOCAL_TIME) {
writeByte((byte) LOCAL_DATE);
long x = ((ValueDate) v).getDateValue();
writeVarLong(x);
......@@ -511,7 +520,7 @@ public class Data {
break;
}
case Value.TIMESTAMP: {
if (SysProperties.STORE_LOCAL_TIME) {
if (STORE_LOCAL_TIME) {
writeByte((byte) LOCAL_TIMESTAMP);
ValueTimestamp ts = (ValueTimestamp) v;
long dateValue = ts.getDateValue();
......@@ -982,7 +991,7 @@ public class Data {
return 1 + getVarIntLen(scale) + getVarIntLen(bytes.length) + bytes.length;
}
case Value.TIME:
if (SysProperties.STORE_LOCAL_TIME) {
if (STORE_LOCAL_TIME) {
long nanos = ((ValueTime) v).getNanos();
long millis = nanos / 1000000;
nanos -= millis * 1000000;
......@@ -990,7 +999,7 @@ public class Data {
}
return 1 + getVarLongLen(DateTimeUtils.getTimeLocalWithoutDst(v.getTime()));
case Value.DATE: {
if (SysProperties.STORE_LOCAL_TIME) {
if (STORE_LOCAL_TIME) {
long dateValue = ((ValueDate) v).getDateValue();
return 1 + getVarLongLen(dateValue);
}
......@@ -998,7 +1007,7 @@ public class Data {
return 1 + getVarLongLen(x / MILLIS_PER_MINUTE);
}
case Value.TIMESTAMP: {
if (SysProperties.STORE_LOCAL_TIME) {
if (STORE_LOCAL_TIME) {
ValueTimestamp ts = (ValueTimestamp) v;
long dateValue = ts.getDateValue();
long nanos = ts.getTimeNanos();
......
......@@ -19,7 +19,6 @@ import java.util.GregorianCalendar;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import org.h2.engine.SysProperties;
import org.h2.test.TestBase;
import org.h2.test.unit.TestDate;
import org.h2.util.DateTimeUtils;
......@@ -156,7 +155,7 @@ public class TestDateStorage extends TestBase {
if (config.memory) {
return;
}
if (!SysProperties.STORE_LOCAL_TIME) {
if (config.mvStore) {
return;
}
String db = getTestName() + ";LOG=0;FILE_LOCK=NO";
......
......@@ -15,8 +15,6 @@ import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.h2.api.ErrorCode;
import org.h2.engine.SysProperties;
import org.h2.store.Data;
import org.h2.test.TestBase;
import org.h2.test.utils.AssertThrows;
import org.h2.util.DateTimeUtils;
......@@ -25,8 +23,6 @@ import org.h2.value.Value;
import org.h2.value.ValueDate;
import org.h2.value.ValueDouble;
import org.h2.value.ValueInt;
import org.h2.value.ValueNull;
import org.h2.value.ValueString;
import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp;
......@@ -57,7 +53,6 @@ public class TestDate extends TestBase {
testValidDate();
testAbsoluteDay();
testCalculateLocalMillis();
testTimeOperationsAcrossTimeZones();
testDateTimeUtils();
}
......@@ -437,62 +432,6 @@ public class TestDate extends TestBase {
}
}
private void testTimeOperationsAcrossTimeZones() {
if (!SysProperties.STORE_LOCAL_TIME) {
return;
}
TimeZone defaultTimeZone = TimeZone.getDefault();
ArrayList<TimeZone> distinct = TestDate.getDistinctTimeZones();
Data d = Data.create(null, 10240);
try {
for (TimeZone tz : distinct) {
TimeZone.setDefault(tz);
DateTimeUtils.resetCalendar();
d.reset();
for (int m = 1; m <= 12; m++) {
for (int h = 0; h <= 23; h++) {
if (h == 0 || h == 2 || h == 3) {
// those hours may not exist for all days in all
// timezones because of daylight saving
continue;
}
String s = "2000-" + (m < 10 ? "0" + m : m) +
"-01 " + (h < 10 ? "0" + h : h) + ":00:00.0";
d.writeValue(ValueString.get(s));
d.writeValue(ValueTimestamp.get(Timestamp.valueOf(s)));
}
}
d.writeValue(ValueNull.INSTANCE);
d.reset();
for (TimeZone target : distinct) {
if ("Pacific/Kiritimati".equals(target.getID())) {
// there is a problem with this time zone, but it seems
// unrelated to this database (possibly wrong timezone
// information?)
continue;
}
TimeZone.setDefault(target);
DateTimeUtils.resetCalendar();
while (true) {
Value v = d.readValue();
if (v == ValueNull.INSTANCE) {
break;
}
String a = v.getString();
String b = d.readValue().getString();
if (!a.equals(b)) {
assertEquals("source: " + tz.getID() + " target: " +
target.getID(), a, b);
}
}
}
}
} finally {
TimeZone.setDefault(defaultTimeZone);
DateTimeUtils.resetCalendar();
}
}
/**
* Get the list of timezones with distinct rules.
*
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论