提交 2deb0e7c authored 作者: Thomas Mueller's avatar Thomas Mueller

Issue 335: Could not run DROP ALL OBJECTS DELETE FILES on older databases with…

Issue 335: Could not run DROP ALL OBJECTS DELETE FILES on older databases with CLOB or BLOB data. The problem was that the metadata table was not locked in some cases, so that a rollback could result in a corrupt database in a database if the lob storage was upgraded.
上级 3da74ed2
...@@ -18,7 +18,12 @@ Change Log ...@@ -18,7 +18,12 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>The JDBC methods PreparedStatement.setTimestamp, setTime, and setDate with a calendar, <ul><li>Issue 335: Could not run DROP ALL OBJECTS DELETE FILES on older databases with CLOB or BLOB data.
The problem was that the metadata table was not locked in some cases, so that
a rollback could result in a corrupt database in a database if the lob storage was upgraded.
</li><li>Source code switching using //## has been simplified.
The Java 1.5 tag has been removed because is no longer needed.
</li><li>The JDBC methods PreparedStatement.setTimestamp, setTime, and setDate with a calendar,
and the methods ResultSet.getTimestamp, getTime, and getDate with a calendar converted and the methods ResultSet.getTimestamp, getTime, and getDate with a calendar converted
the value in the wrong way, so that for some timestamps the converted value was wrong the value in the wrong way, so that for some timestamps the converted value was wrong
(where summertime starts, one hour per year). (where summertime starts, one hour per year).
......
...@@ -89,6 +89,7 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -89,6 +89,7 @@ public class AlterTableAddConstraint extends SchemaCommand {
throw DbException.get(ErrorCode.CONSTRAINT_ALREADY_EXISTS_1, constraintName); throw DbException.get(ErrorCode.CONSTRAINT_ALREADY_EXISTS_1, constraintName);
} }
session.getUser().checkRight(table, Right.ALL); session.getUser().checkRight(table, Right.ALL);
db.lockMeta(session);
table.lock(session, true, true); table.lock(session, true, true);
Constraint constraint; Constraint constraint;
switch (type) { switch (type) {
......
...@@ -127,6 +127,10 @@ public class CreateTable extends SchemaCommand { ...@@ -127,6 +127,10 @@ public class CreateTable extends SchemaCommand {
data.id = getObjectId(); data.id = getObjectId();
data.create = create; data.create = create;
data.session = session; data.session = session;
boolean isSessionTemporary = data.temporary && !data.globalTemporary;
if (!isSessionTemporary) {
db.lockMeta(session);
}
Table table = getSchema().createTable(data); Table table = getSchema().createTable(data);
ArrayList<Sequence> sequences = New.arrayList(); ArrayList<Sequence> sequences = New.arrayList();
for (Column c : data.columns) { for (Column c : data.columns) {
...@@ -140,7 +144,7 @@ public class CreateTable extends SchemaCommand { ...@@ -140,7 +144,7 @@ public class CreateTable extends SchemaCommand {
} }
} }
table.setComment(comment); table.setComment(comment);
if (data.temporary && !data.globalTemporary) { if (isSessionTemporary) {
if (onCommitDrop) { if (onCommitDrop) {
table.setOnCommitDrop(true); table.setOnCommitDrop(true);
} }
...@@ -149,6 +153,7 @@ public class CreateTable extends SchemaCommand { ...@@ -149,6 +153,7 @@ public class CreateTable extends SchemaCommand {
} }
session.addLocalTempTable(table); session.addLocalTempTable(table);
} else { } else {
db.lockMeta(session);
db.addSchemaObject(session, table); db.addSchemaObject(session, table);
} }
try { try {
......
...@@ -45,6 +45,7 @@ public class DropDatabase extends DefineCommand { ...@@ -45,6 +45,7 @@ public class DropDatabase extends DefineCommand {
session.getUser().checkAdmin(); session.getUser().checkAdmin();
session.commit(true); session.commit(true);
Database db = session.getDatabase(); Database db = session.getDatabase();
db.lockMeta(session);
// TODO local temp tables are not removed // TODO local temp tables are not removed
for (Schema schema : db.getAllSchemas()) { for (Schema schema : db.getAllSchemas()) {
if (schema.canDrop()) { if (schema.canDrop()) {
......
...@@ -99,6 +99,7 @@ public class DropTable extends SchemaCommand { ...@@ -99,6 +99,7 @@ public class DropTable extends SchemaCommand {
if (table != null) { if (table != null) {
table.setModified(); table.setModified();
Database db = session.getDatabase(); Database db = session.getDatabase();
db.lockMeta(session);
db.removeSchemaObject(session, table); db.removeSchemaObject(session, table);
} }
if (next != null) { if (next != null) {
......
...@@ -614,6 +614,7 @@ public class Database implements DataHandler { ...@@ -614,6 +614,7 @@ public class Database implements DataHandler {
if (settings.get(name) == null) { if (settings.get(name) == null) {
Setting setting = new Setting(this, allocateObjectId(), name); Setting setting = new Setting(this, allocateObjectId(), name);
setting.setIntValue(Constants.BUILD_ID); setting.setIntValue(Constants.BUILD_ID);
lockMeta(systemSession);
addDatabaseObject(systemSession, setting); addDatabaseObject(systemSession, setting);
} }
// mark all ids used in the page store // mark all ids used in the page store
...@@ -627,6 +628,7 @@ public class Database implements DataHandler { ...@@ -627,6 +628,7 @@ public class Database implements DataHandler {
} }
} }
} }
getLobStorage().init();
systemSession.commit(true); systemSession.commit(true);
trace.info("opened {0}", databaseName); trace.info("opened {0}", databaseName);
afterWriting(); afterWriting();
...@@ -710,7 +712,9 @@ public class Database implements DataHandler { ...@@ -710,7 +712,9 @@ public class Database implements DataHandler {
MetaRecord rec = new MetaRecord(obj); MetaRecord rec = new MetaRecord(obj);
rec.setRecord(r); rec.setRecord(r);
objectIds.set(id); objectIds.set(id);
meta.lock(session, true, true); if (SysProperties.CHECK) {
verifyMetaLocked(session);
}
meta.addRow(session, r); meta.addRow(session, r);
if (isMultiVersion()) { if (isMultiVersion()) {
// TODO this should work without MVCC, but avoid risks at the moment // TODO this should work without MVCC, but avoid risks at the moment
...@@ -719,6 +723,27 @@ public class Database implements DataHandler { ...@@ -719,6 +723,27 @@ public class Database implements DataHandler {
} }
} }
public void verifyMetaLocked(Session session) {
if (!lockMeta(session) && lockMode != 0) {
throw DbException.throwInternalError();
}
}
/**
* Lock the metadata table for updates.
*
* @param session the session
* @return whether it was already locked before by this session
*/
public synchronized boolean lockMeta(Session session) {
if (meta == null) {
return true;
}
boolean wasLocked = meta.isLockedExclusivelyBy(session);
meta.lock(session, true, true);
return wasLocked;
}
/** /**
* Remove the given object from the meta data. * Remove the given object from the meta data.
* *
...@@ -729,10 +754,14 @@ public class Database implements DataHandler { ...@@ -729,10 +754,14 @@ public class Database implements DataHandler {
if (id > 0 && !starting) { if (id > 0 && !starting) {
SearchRow r = meta.getTemplateSimpleRow(false); SearchRow r = meta.getTemplateSimpleRow(false);
r.setValue(0, ValueInt.get(id)); r.setValue(0, ValueInt.get(id));
boolean wasLocked = meta.isLockedExclusivelyBy(session); boolean wasLocked = lockMeta(session);
meta.lock(session, true, true);
Cursor cursor = metaIdIndex.find(session, r, r); Cursor cursor = metaIdIndex.find(session, r, r);
if (cursor.next()) { if (cursor.next()) {
if (SysProperties.CHECK) {
if (lockMode != 0 && !wasLocked) {
throw DbException.throwInternalError();
}
}
Row found = cursor.get(); Row found = cursor.get();
meta.removeRow(session, found); meta.removeRow(session, found);
if (isMultiVersion()) { if (isMultiVersion()) {
...@@ -798,6 +827,7 @@ public class Database implements DataHandler { ...@@ -798,6 +827,7 @@ public class Database implements DataHandler {
if (id > 0 && !starting) { if (id > 0 && !starting) {
checkWritingAllowed(); checkWritingAllowed();
} }
lockMeta(session);
obj.getSchema().add(obj); obj.getSchema().add(obj);
addMeta(session, obj); addMeta(session, obj);
} }
...@@ -824,6 +854,7 @@ public class Database implements DataHandler { ...@@ -824,6 +854,7 @@ public class Database implements DataHandler {
if (SysProperties.CHECK && map.get(name) != null) { if (SysProperties.CHECK && map.get(name) != null) {
DbException.throwInternalError("object already exists"); DbException.throwInternalError("object already exists");
} }
lockMeta(session);
addMeta(session, obj); addMeta(session, obj);
map.put(name, obj); map.put(name, obj);
} }
...@@ -1131,6 +1162,7 @@ public class Database implements DataHandler { ...@@ -1131,6 +1162,7 @@ public class Database implements DataHandler {
try { try {
pageStore.checkpoint(); pageStore.checkpoint();
if (!readOnly) { if (!readOnly) {
lockMeta(pageStore.getSystemSession());
pageStore.compact(compactMode); pageStore.compact(compactMode);
} }
} catch (DbException e) { } catch (DbException e) {
...@@ -1357,6 +1389,7 @@ public class Database implements DataHandler { ...@@ -1357,6 +1389,7 @@ public class Database implements DataHandler {
* @param obj the database object * @param obj the database object
*/ */
public synchronized void update(Session session, DbObject obj) { public synchronized void update(Session session, DbObject obj) {
lockMeta(session);
int id = obj.getId(); int id = obj.getId();
removeMeta(session, id); removeMeta(session, id);
addMeta(session, obj); addMeta(session, obj);
...@@ -1413,6 +1446,7 @@ public class Database implements DataHandler { ...@@ -1413,6 +1446,7 @@ public class Database implements DataHandler {
} }
obj.checkRename(); obj.checkRename();
int id = obj.getId(); int id = obj.getId();
lockMeta(session);
removeMeta(session, id); removeMeta(session, id);
map.remove(obj.getName()); map.remove(obj.getName());
obj.rename(newName); obj.rename(newName);
...@@ -1479,6 +1513,7 @@ public class Database implements DataHandler { ...@@ -1479,6 +1513,7 @@ public class Database implements DataHandler {
DbException.throwInternalError("not found: " + objName); DbException.throwInternalError("not found: " + objName);
} }
Comment comment = findComment(obj); Comment comment = findComment(obj);
lockMeta(session);
if (comment != null) { if (comment != null) {
removeDatabaseObject(session, comment); removeDatabaseObject(session, comment);
} }
...@@ -1550,6 +1585,7 @@ public class Database implements DataHandler { ...@@ -1550,6 +1585,7 @@ public class Database implements DataHandler {
} }
} }
checkWritingAllowed(); checkWritingAllowed();
lockMeta(session);
Comment comment = findComment(obj); Comment comment = findComment(obj);
if (comment != null) { if (comment != null) {
removeDatabaseObject(session, comment); removeDatabaseObject(session, comment);
...@@ -1592,6 +1628,7 @@ public class Database implements DataHandler { ...@@ -1592,6 +1628,7 @@ public class Database implements DataHandler {
} }
public synchronized void setMasterUser(User user) { public synchronized void setMasterUser(User user) {
lockMeta(systemSession);
addDatabaseObject(systemSession, user); addDatabaseObject(systemSession, user);
systemSession.commit(true); systemSession.commit(true);
} }
......
...@@ -529,6 +529,9 @@ public class Schema extends DbObjectBase { ...@@ -529,6 +529,9 @@ public class Schema extends DbObjectBase {
*/ */
public Table createTable(CreateTableData data) { public Table createTable(CreateTableData data) {
synchronized (database) { synchronized (database) {
if (!data.temporary || data.globalTemporary) {
database.lockMeta(data.session);
}
data.schema = this; data.schema = this;
if (data.tableEngine != null) { if (data.tableEngine != null) {
TableEngine engine; TableEngine engine;
......
...@@ -1674,6 +1674,11 @@ public class PageStore implements CacheWriter { ...@@ -1674,6 +1674,11 @@ public class PageStore implements CacheWriter {
if (table.isTemporary()) { if (table.isTemporary()) {
options += "temp"; options += "temp";
} }
if (SysProperties.CHECK) {
if (!table.isTemporary()) {
database.verifyMetaLocked(session);
}
}
options += ","; options += ",";
if (index instanceof PageDelegateIndex) { if (index instanceof PageDelegateIndex) {
options += "d"; options += "d";
...@@ -1696,6 +1701,11 @@ public class PageStore implements CacheWriter { ...@@ -1696,6 +1701,11 @@ public class PageStore implements CacheWriter {
* @param session the session * @param session the session
*/ */
public synchronized void removeMeta(Index index, Session session) { public synchronized void removeMeta(Index index, Session session) {
if (SysProperties.CHECK) {
if (!index.getTable().isTemporary()) {
database.verifyMetaLocked(session);
}
}
if (!recoveryRunning) { if (!recoveryRunning) {
removeMetaIndex(index, session); removeMetaIndex(index, session);
metaObjects.remove(index.getId()); metaObjects.remove(index.getId());
...@@ -1896,4 +1906,8 @@ public class PageStore implements CacheWriter { ...@@ -1896,4 +1906,8 @@ public class PageStore implements CacheWriter {
return f; return f;
} }
public Session getSystemSession() {
return systemSession;
}
} }
...@@ -19,7 +19,6 @@ import org.h2.constant.SysProperties; ...@@ -19,7 +19,6 @@ import org.h2.constant.SysProperties;
import org.h2.constraint.Constraint; import org.h2.constraint.Constraint;
import org.h2.constraint.ConstraintReferential; import org.h2.constraint.ConstraintReferential;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.engine.DbObject; import org.h2.engine.DbObject;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.index.Cursor; import org.h2.index.Cursor;
...@@ -80,14 +79,6 @@ public class RegularTable extends TableBase { ...@@ -80,14 +79,6 @@ public class RegularTable extends TableBase {
containsLargeObject = true; containsLargeObject = true;
} }
} }
if (containsLargeObject) {
Database db = data.session.getDatabase();
if (!db.isStarting()) {
// the lob tables are already created
// if the database is starting
db.getLobStorage().init();
}
}
if (data.persistData && database.isPersistent()) { if (data.persistData && database.isPersistent()) {
mainIndex = new PageDataIndex(this, data.id, mainIndex = new PageDataIndex(this, data.id,
IndexColumn.wrap(getColumns()), IndexColumn.wrap(getColumns()),
...@@ -211,6 +202,10 @@ public class RegularTable extends TableBase { ...@@ -211,6 +202,10 @@ public class RegularTable extends TableBase {
column.setPrimaryKey(true); column.setPrimaryKey(true);
} }
} }
boolean isSessionTemporary = isTemporary() && !isGlobalTemporary();
if (!isSessionTemporary) {
database.lockMeta(session);
}
Index index; Index index;
if (isPersistIndexes() && indexType.isPersistent()) { if (isPersistIndexes() && indexType.isPersistent()) {
int mainIndexColumn; int mainIndexColumn;
...@@ -280,11 +275,10 @@ public class RegularTable extends TableBase { ...@@ -280,11 +275,10 @@ public class RegularTable extends TableBase {
throw e; throw e;
} }
} }
boolean temporary = isTemporary(); index.setTemporary(isTemporary());
index.setTemporary(temporary);
if (index.getCreateSQL() != null) { if (index.getCreateSQL() != null) {
index.setComment(indexComment); index.setComment(indexComment);
if (temporary && !isGlobalTemporary()) { if (isSessionTemporary) {
session.addLocalTempTableIndex(index); session.addLocalTempTableIndex(index);
} else { } else {
database.addSchemaObject(session, index); database.addSchemaObject(session, index);
...@@ -657,6 +651,7 @@ public class RegularTable extends TableBase { ...@@ -657,6 +651,7 @@ public class RegularTable extends TableBase {
// unfortunately, the data is gone on rollback // unfortunately, the data is gone on rollback
truncate(session); truncate(session);
database.getLobStorage().removeAllForTable(getId()); database.getLobStorage().removeAllForTable(getId());
database.lockMeta(session);
} }
super.removeChildrenAndResources(session); super.removeChildrenAndResources(session);
// go backwards because database.removeIndex will call table.removeIndex // go backwards because database.removeIndex will call table.removeIndex
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论