提交 ac334431 authored 作者: Noel Grandin's avatar Noel Grandin

#394: Recover tool places COLLATION and BINARY_COLLATION after temporary tables

上级 2da82c8e
...@@ -21,6 +21,8 @@ Change Log ...@@ -21,6 +21,8 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>Issue #394: Recover tool places COLLATION and BINARY_COLLATION after temporary tables
</li>
<li>Improve the script-based unit testing to check the error code of the exception thrown. <li>Improve the script-based unit testing to check the error code of the exception thrown.
</li> </li>
<li>Issue #1041: Support OR syntax while creating trigger <li>Issue #1041: Support OR syntax while creating trigger
......
...@@ -2568,7 +2568,8 @@ public class Database implements DataHandler { ...@@ -2568,7 +2568,8 @@ public class Database implements DataHandler {
} }
/** /**
* Get the first user defined table. * Get the first user defined table, excluding the LOB_BLOCKS table that the
* Recover tool creates.
* *
* @return the table or null if no table is defined * @return the table or null if no table is defined
*/ */
...@@ -2579,6 +2580,11 @@ public class Database implements DataHandler { ...@@ -2579,6 +2580,11 @@ public class Database implements DataHandler {
// LOB tables // LOB tables
continue; continue;
} }
// exclude the LOB_MAP that the Recover tool creates
if (table.getName().equals("LOB_BLOCKS") && table.getSchema()
.getName().equals("INFORMATION_SCHEMA")) {
continue;
}
return table; return table;
} }
} }
......
...@@ -42,9 +42,9 @@ import org.h2.mvstore.MVMap; ...@@ -42,9 +42,9 @@ import org.h2.mvstore.MVMap;
import org.h2.mvstore.MVStore; import org.h2.mvstore.MVStore;
import org.h2.mvstore.MVStoreTool; import org.h2.mvstore.MVStoreTool;
import org.h2.mvstore.StreamStore; import org.h2.mvstore.StreamStore;
import org.h2.mvstore.tx.TransactionStore;
import org.h2.mvstore.tx.TransactionMap;
import org.h2.mvstore.db.ValueDataType; import org.h2.mvstore.db.ValueDataType;
import org.h2.mvstore.tx.TransactionMap;
import org.h2.mvstore.tx.TransactionStore;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.RowFactory; import org.h2.result.RowFactory;
import org.h2.result.SimpleRow; import org.h2.result.SimpleRow;
...@@ -555,6 +555,7 @@ public class Recover extends Tool implements DataHandler { ...@@ -555,6 +555,7 @@ public class Recover extends Tool implements DataHandler {
schema.clear(); schema.clear();
objectIdSet = new HashSet<>(); objectIdSet = new HashSet<>();
dumpPageStore(writer, pageCount); dumpPageStore(writer, pageCount);
writeSchemaSET(writer);
writeSchema(writer); writeSchema(writer);
try { try {
dumpPageLogStream(writer, logKey, logFirstTrunkPage, dumpPageLogStream(writer, logKey, logFirstTrunkPage,
...@@ -616,11 +617,51 @@ public class Recover extends Tool implements DataHandler { ...@@ -616,11 +617,51 @@ public class Recover extends Tool implements DataHandler {
writeError(writer, e); writeError(writer, e);
} }
try { try {
// extract the metadata so we can dump the settings
for (String mapName : mv.getMapNames()) {
if (!mapName.startsWith("table.")) {
continue;
}
String tableId = mapName.substring("table.".length());
if (Integer.parseInt(tableId) == 0) {
ValueDataType keyType = new ValueDataType(
null, this, null);
ValueDataType valueType = new ValueDataType(
null, this, null);
TransactionMap<Value, Value> dataMap = store.begin().openMap(
mapName, keyType, valueType);
Iterator<Value> dataIt = dataMap.keyIterator(null);
while (dataIt.hasNext()) {
Value rowId = dataIt.next();
Value[] values = ((ValueArray) dataMap.get(rowId))
.getList();
try {
SimpleRow r = new SimpleRow(values);
MetaRecord meta = new MetaRecord(r);
schema.add(meta);
if (meta.getObjectType() == DbObject.TABLE_OR_VIEW) {
String sql = values[3].getString();
String name = extractTableOrViewName(sql);
tableMap.put(meta.getId(), name);
}
} catch (Throwable t) {
writeError(writer, t);
}
}
}
}
// Have to do these before the tables because settings like COLLATION may affect some of them,
// and we can't change settings after we have created user tables
writeSchemaSET(writer);
writer.println("---- Table Data ----");
for (String mapName : mv.getMapNames()) { for (String mapName : mv.getMapNames()) {
if (!mapName.startsWith("table.")) { if (!mapName.startsWith("table.")) {
continue; continue;
} }
String tableId = mapName.substring("table.".length()); String tableId = mapName.substring("table.".length());
if (Integer.parseInt(tableId) == 0) {
continue;
}
ValueDataType keyType = new ValueDataType( ValueDataType keyType = new ValueDataType(
null, this, null); null, this, null);
ValueDataType valueType = new ValueDataType( ValueDataType valueType = new ValueDataType(
...@@ -655,20 +696,6 @@ public class Recover extends Tool implements DataHandler { ...@@ -655,20 +696,6 @@ public class Recover extends Tool implements DataHandler {
} }
buff.append(");"); buff.append(");");
writer.println(buff.toString()); writer.println(buff.toString());
if (storageId == 0) {
try {
SimpleRow r = new SimpleRow(values);
MetaRecord meta = new MetaRecord(r);
schema.add(meta);
if (meta.getObjectType() == DbObject.TABLE_OR_VIEW) {
String sql = values[3].getString();
String name = extractTableOrViewName(sql);
tableMap.put(meta.getId(), name);
}
} catch (Throwable t) {
writeError(writer, t);
}
}
} }
} }
writeSchema(writer); writeSchema(writer);
...@@ -1513,11 +1540,22 @@ public class Recover extends Tool implements DataHandler { ...@@ -1513,11 +1540,22 @@ public class Recover extends Tool implements DataHandler {
columnTypeMap = new HashMap<>(); columnTypeMap = new HashMap<>();
} }
private void writeSchemaSET(PrintWriter writer) {
writer.println("---- Schema SET ----");
for (MetaRecord m : schema) {
if (m.getObjectType() == DbObject.SETTING) {
String sql = m.getSQL();
writer.println(sql + ";");
}
}
}
private void writeSchema(PrintWriter writer) { private void writeSchema(PrintWriter writer) {
writer.println("---- Schema ----"); writer.println("---- Schema ----");
Collections.sort(schema); Collections.sort(schema);
for (MetaRecord m : schema) { for (MetaRecord m : schema) {
if (!isSchemaObjectTypeDelayed(m)) { if (m.getObjectType() != DbObject.SETTING
&& !isSchemaObjectTypeDelayed(m)) {
// create, but not referential integrity constraints and so on // create, but not referential integrity constraints and so on
// because they could fail on duplicate keys // because they could fail on duplicate keys
String sql = m.getSQL(); String sql = m.getSQL();
......
...@@ -1398,7 +1398,7 @@ public abstract class TestBase { ...@@ -1398,7 +1398,7 @@ public abstract class TestBase {
} }
/** /**
* Check if two databases contain the same met data. * Check if two databases contain the same meta data.
* *
* @param stat1 the connection to the first database * @param stat1 the connection to the first database
* @param stat2 the connection to the second database * @param stat2 the connection to the second database
......
...@@ -50,6 +50,7 @@ public class TestRecovery extends TestBase { ...@@ -50,6 +50,7 @@ public class TestRecovery extends TestBase {
testWithTransactionLog(); testWithTransactionLog();
testCompressedAndUncompressed(); testCompressedAndUncompressed();
testRunScript(); testRunScript();
testRunScript2();
} }
private void testRecoverTestMode() throws Exception { private void testRecoverTestMode() throws Exception {
...@@ -318,4 +319,43 @@ public class TestRecovery extends TestBase { ...@@ -318,4 +319,43 @@ public class TestRecovery extends TestBase {
FileUtils.deleteRecursive(dir, false); FileUtils.deleteRecursive(dir, false);
} }
private void testRunScript2() throws SQLException {
DeleteDbFiles.execute(getBaseDir(), "recovery", true);
DeleteDbFiles.execute(getBaseDir(), "recovery2", true);
org.h2.Driver.load();
Connection conn = getConnection("recovery");
Statement stat = conn.createStatement();
stat.execute("SET COLLATION EN");
stat.execute("SET BINARY_COLLATION UNSIGNED");
stat.execute("CREATE TABLE TEST(A VARCHAR)");
conn.close();
final Recover recover = new Recover();
final ByteArrayOutputStream buff = new ByteArrayOutputStream(); // capture the console output
recover.setOut(new PrintStream(buff));
recover.runTool("-dir", getBaseDir(), "-db", "recovery", "-trace");
String consoleOut = new String(buff.toByteArray());
assertContains(consoleOut, "Created file");
Connection conn2 = getConnection("recovery2");
Statement stat2 = conn2.createStatement();
stat2.execute("runscript from '" + getBaseDir() + "/recovery.h2.sql'");
stat2.execute("select * from test");
conn2.close();
conn = getConnection("recovery");
stat = conn.createStatement();
conn2 = getConnection("recovery2");
stat2 = conn2.createStatement();
assertEqualDatabases(stat, stat2);
conn.close();
conn2.close();
deleteDb("recovery");
deleteDb("recovery2");
FileUtils.delete(getBaseDir() + "/recovery.h2.sql");
String dir = getBaseDir() + "/recovery.lobs.db";
FileUtils.deleteRecursive(dir, false);
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论