提交 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
<h2>Next Version (unreleased)</h2>
<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>
<li>Issue #1041: Support OR syntax while creating trigger
......
......@@ -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
*/
......@@ -2579,6 +2580,11 @@ public class Database implements DataHandler {
// LOB tables
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;
}
}
......
......@@ -42,9 +42,9 @@ import org.h2.mvstore.MVMap;
import org.h2.mvstore.MVStore;
import org.h2.mvstore.MVStoreTool;
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.tx.TransactionMap;
import org.h2.mvstore.tx.TransactionStore;
import org.h2.result.Row;
import org.h2.result.RowFactory;
import org.h2.result.SimpleRow;
......@@ -555,6 +555,7 @@ public class Recover extends Tool implements DataHandler {
schema.clear();
objectIdSet = new HashSet<>();
dumpPageStore(writer, pageCount);
writeSchemaSET(writer);
writeSchema(writer);
try {
dumpPageLogStream(writer, logKey, logFirstTrunkPage,
......@@ -616,11 +617,51 @@ public class Recover extends Tool implements DataHandler {
writeError(writer, e);
}
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()) {
if (!mapName.startsWith("table.")) {
continue;
}
String tableId = mapName.substring("table.".length());
if (Integer.parseInt(tableId) == 0) {
continue;
}
ValueDataType keyType = new ValueDataType(
null, this, null);
ValueDataType valueType = new ValueDataType(
......@@ -655,20 +696,6 @@ public class Recover extends Tool implements DataHandler {
}
buff.append(");");
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);
......@@ -1513,11 +1540,22 @@ public class Recover extends Tool implements DataHandler {
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) {
writer.println("---- Schema ----");
Collections.sort(schema);
for (MetaRecord m : schema) {
if (!isSchemaObjectTypeDelayed(m)) {
if (m.getObjectType() != DbObject.SETTING
&& !isSchemaObjectTypeDelayed(m)) {
// create, but not referential integrity constraints and so on
// because they could fail on duplicate keys
String sql = m.getSQL();
......
......@@ -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 stat2 the connection to the second database
......
......@@ -50,6 +50,7 @@ public class TestRecovery extends TestBase {
testWithTransactionLog();
testCompressedAndUncompressed();
testRunScript();
testRunScript2();
}
private void testRecoverTestMode() throws Exception {
......@@ -318,4 +319,43 @@ public class TestRecovery extends TestBase {
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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论