提交 7398ebec authored 作者: Thomas Mueller's avatar Thomas Mueller

Constraints for local temporary tables now session scoped.

上级 6d50ee90
...@@ -18,7 +18,9 @@ Change Log ...@@ -18,7 +18,9 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>When using the auto-server mode, and if the lock file was modified in the future, <ul><li>Constraints for local temporary tables now session scoped. So far they were global.
Thanks a lot to Eric Faulhaber for finding and fixing this problem!
</li><li>When using the auto-server mode, and if the lock file was modified in the future,
the wrong exception was thrown ('Connection is broken' instead of 'Error opening database: Lock file modified in the future'). the wrong exception was thrown ('Connection is broken' instead of 'Error opening database: Lock file modified in the future').
</li></ul> </li></ul>
......
...@@ -78,7 +78,7 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -78,7 +78,7 @@ public class AlterTableAddConstraint extends SchemaCommand {
private String generateConstraintName(Table table) { private String generateConstraintName(Table table) {
if (constraintName == null) { if (constraintName == null) {
constraintName = getSchema().getUniqueConstraintName(table); constraintName = getSchema().getUniqueConstraintName(session, table);
} }
return constraintName; return constraintName;
} }
...@@ -100,7 +100,7 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -100,7 +100,7 @@ public class AlterTableAddConstraint extends SchemaCommand {
session.commit(true); session.commit(true);
Database db = session.getDatabase(); Database db = session.getDatabase();
Table table = getSchema().getTableOrView(session, tableName); Table table = getSchema().getTableOrView(session, tableName);
if (getSchema().findConstraint(constraintName) != null) { if (getSchema().findConstraint(session, constraintName) != null) {
if (ifNotExists) { if (ifNotExists) {
return 0; return 0;
} }
...@@ -248,7 +248,11 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -248,7 +248,11 @@ public class AlterTableAddConstraint extends SchemaCommand {
} }
// parent relationship is already set with addConstraint // parent relationship is already set with addConstraint
constraint.setComment(comment); constraint.setComment(comment);
db.addSchemaObject(session, constraint); if (table.getTemporary() && !table.getGlobalTemporary()) {
session.addLocalTempTableConstraint(constraint);
} else {
db.addSchemaObject(session, constraint);
}
table.addConstraint(constraint); table.addConstraint(constraint);
return 0; return 0;
} }
......
...@@ -35,7 +35,7 @@ public class AlterTableDropConstraint extends SchemaCommand { ...@@ -35,7 +35,7 @@ public class AlterTableDropConstraint extends SchemaCommand {
public int update() throws SQLException { public int update() throws SQLException {
session.commit(true); session.commit(true);
Constraint constraint = getSchema().findConstraint(constraintName); Constraint constraint = getSchema().findConstraint(session, constraintName);
if (constraint == null) { if (constraint == null) {
if (!ifExists) { if (!ifExists) {
throw Message.getSQLException(ErrorCode.CONSTRAINT_NOT_FOUND_1, constraintName); throw Message.getSQLException(ErrorCode.CONSTRAINT_NOT_FOUND_1, constraintName);
......
...@@ -20,6 +20,7 @@ import org.h2.api.DatabaseEventListener; ...@@ -20,6 +20,7 @@ import org.h2.api.DatabaseEventListener;
import org.h2.command.dml.SetTypes; import org.h2.command.dml.SetTypes;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.constraint.Constraint;
import org.h2.index.Cursor; import org.h2.index.Cursor;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.index.IndexType; import org.h2.index.IndexType;
...@@ -1529,18 +1530,27 @@ public class Database implements DataHandler { ...@@ -1529,18 +1530,27 @@ public class Database implements DataHandler {
* @param obj the object to be removed * @param obj the object to be removed
*/ */
public synchronized void removeSchemaObject(Session session, SchemaObject obj) throws SQLException { public synchronized void removeSchemaObject(Session session, SchemaObject obj) throws SQLException {
if (obj.getType() == DbObject.TABLE_OR_VIEW) { int type = obj.getType();
if (type == DbObject.TABLE_OR_VIEW) {
Table table = (Table) obj; Table table = (Table) obj;
if (table.getTemporary() && !table.getGlobalTemporary()) { if (table.getTemporary() && !table.getGlobalTemporary()) {
session.removeLocalTempTable(table); session.removeLocalTempTable(table);
return; return;
} }
} else if (obj.getType() == DbObject.INDEX) { } else if (type == DbObject.INDEX) {
Index index = (Index) obj; Index index = (Index) obj;
if (index.getTable().getTemporary() && !index.getTable().getGlobalTemporary()) { Table table = index.getTable();
if (table.getTemporary() && !table.getGlobalTemporary()) {
session.removeLocalTempTableIndex(index); session.removeLocalTempTableIndex(index);
return; return;
} }
} else if (type == DbObject.CONSTRAINT) {
Constraint constraint = (Constraint) obj;
Table table = constraint.getTable();
if (table.getTemporary() && !table.getGlobalTemporary()) {
session.removeLocalTempTableConstraint(constraint);
return;
}
} }
checkWritingAllowed(); checkWritingAllowed();
Comment comment = findComment(obj); Comment comment = findComment(obj);
......
...@@ -20,6 +20,7 @@ import org.h2.command.Prepared; ...@@ -20,6 +20,7 @@ import org.h2.command.Prepared;
import org.h2.command.dml.SetTypes; import org.h2.command.dml.SetTypes;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.constraint.Constraint;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.jdbc.JdbcConnection; import org.h2.jdbc.JdbcConnection;
import org.h2.log.InDoubtTransaction; import org.h2.log.InDoubtTransaction;
...@@ -67,6 +68,7 @@ public class Session implements SessionInterface { ...@@ -67,6 +68,7 @@ public class Session implements SessionInterface {
private Exception stackTrace = new Exception(); private Exception stackTrace = new Exception();
private HashMap localTempTables; private HashMap localTempTables;
private HashMap localTempTableIndexes; private HashMap localTempTableIndexes;
private HashMap localTempTableConstraints;
private int throttle; private int throttle;
private long lastThrottle; private long lastThrottle;
private Command currentCommand; private Command currentCommand;
...@@ -266,6 +268,62 @@ public class Session implements SessionInterface { ...@@ -266,6 +268,62 @@ public class Session implements SessionInterface {
index.removeChildrenAndResources(this); index.removeChildrenAndResources(this);
} }
} }
/**
* Get the local temporary constraint if one exists with that name, or
* null if not.
*
* @param name the constraint name
* @return the constraint, or null
*/
public Constraint findLocalTempTableConstraint(String name) {
if (localTempTableConstraints == null) {
return null;
}
return (Constraint) localTempTableConstraints.get(name);
}
/**
* Get the map of constraints for all constraints on local, temporary
* tables, if any. The map's keys are the constraints' names.
*
* @return the map of constraints, or null
*/
public HashMap getLocalTempTableConstraints() {
if (localTempTableConstraints == null) {
return new HashMap();
}
return localTempTableConstraints;
}
/**
* Add a local temporary constraint to this session.
*
* @param constraint the constraint to add
* @throws SQLException if a constraint with the same name already exists
*/
public void addLocalTempTableConstraint(Constraint constraint) throws SQLException {
if (localTempTableConstraints == null) {
localTempTableConstraints = new HashMap();
}
String name = constraint.getName();
if (localTempTableConstraints.get(name) != null) {
throw Message.getSQLException(ErrorCode.CONSTRAINT_ALREADY_EXISTS_1, constraint.getSQL());
}
localTempTableConstraints.put(name, constraint);
}
/**
* Drop and remove the given local temporary constraint from this session.
*
* @param constraint the constraint
*/
public void removeLocalTempTableConstraint(Constraint constraint) throws SQLException {
if (localTempTableConstraints != null) {
localTempTableConstraints.remove(constraint.getName());
constraint.removeChildrenAndResources(this);
}
}
protected void finalize() { protected void finalize() {
if (!SysProperties.runFinalize) { if (!SysProperties.runFinalize) {
......
...@@ -262,11 +262,16 @@ public class Schema extends DbObjectBase { ...@@ -262,11 +262,16 @@ public class Schema extends DbObjectBase {
* Try to find a constraint with this name. This method returns null if no * Try to find a constraint with this name. This method returns null if no
* object with this name exists. * object with this name exists.
* *
* @param constraintName the object name * @param session the session
* @param name the object name
* @return the object or null * @return the object or null
*/ */
public Constraint findConstraint(String constraintName) { public Constraint findConstraint(Session session, String name) {
return (Constraint) constraints.get(constraintName); Constraint constraint = (Constraint) constraints.get(name);
if (constraint == null) {
constraint = session.findLocalTempTableConstraint(name);
}
return constraint;
} }
/** /**
...@@ -287,41 +292,52 @@ public class Schema extends DbObjectBase { ...@@ -287,41 +292,52 @@ public class Schema extends DbObjectBase {
*/ */
public void freeUniqueName(String name) { public void freeUniqueName(String name) {
if (name != null) { if (name != null) {
temporaryUniqueNames.remove(name); synchronized (temporaryUniqueNames) {
temporaryUniqueNames.remove(name);
}
} }
} }
private String getUniqueName(DbObject obj, HashMap map, String prefix) { private String getUniqueName(DbObject obj, HashMap map, String prefix) {
String hash = Integer.toHexString(obj.getName().hashCode()).toUpperCase(); String hash = Integer.toHexString(obj.getName().hashCode()).toUpperCase();
String name = null; String name = null;
for (int i = 1; i < hash.length(); i++) { synchronized (temporaryUniqueNames) {
name = prefix + hash.substring(0, i); for (int i = 1; i < hash.length(); i++) {
if (!map.containsKey(name) && !temporaryUniqueNames.contains(name)) { name = prefix + hash.substring(0, i);
break;
}
name = null;
}
if (name == null) {
prefix = prefix + hash + "_";
for (int i = 0;; i++) {
name = prefix + i;
if (!map.containsKey(name) && !temporaryUniqueNames.contains(name)) { if (!map.containsKey(name) && !temporaryUniqueNames.contains(name)) {
break; break;
} }
name = null;
}
if (name == null) {
prefix = prefix + hash + "_";
for (int i = 0;; i++) {
name = prefix + i;
if (!map.containsKey(name) && !temporaryUniqueNames.contains(name)) {
break;
}
}
} }
temporaryUniqueNames.add(name);
} }
temporaryUniqueNames.add(name);
return name; return name;
} }
/** /**
* Create a unique constraint name. * Create a unique constraint name.
* *
* @param session the session
* @param table the constraint table * @param table the constraint table
* @return the unique name * @return the unique name
*/ */
public String getUniqueConstraintName(Table table) { public String getUniqueConstraintName(Session session, Table table) {
return getUniqueName(table, constraints, "CONSTRAINT_"); HashMap tableConstraints;
if (table.getTemporary() && !table.getGlobalTemporary()) {
tableConstraints = session.getLocalTempTableConstraints();
} else {
tableConstraints = constraints;
}
return getUniqueName(table, tableConstraints, "CONSTRAINT_");
} }
/** /**
......
...@@ -31,6 +31,7 @@ public class TestTempTables extends TestBase { ...@@ -31,6 +31,7 @@ public class TestTempTables extends TestBase {
deleteDb("tempTables"); deleteDb("tempTables");
Connection c1 = getConnection("tempTables"); Connection c1 = getConnection("tempTables");
Connection c2 = getConnection("tempTables"); Connection c2 = getConnection("tempTables");
testConstraints(c1, c2);
testTables(c1, c2); testTables(c1, c2);
testIndexes(c1, c2); testIndexes(c1, c2);
c1.close(); c1.close();
...@@ -38,6 +39,16 @@ public class TestTempTables extends TestBase { ...@@ -38,6 +39,16 @@ public class TestTempTables extends TestBase {
deleteDb("tempTables"); deleteDb("tempTables");
} }
private void testConstraints(Connection conn1, Connection conn2) throws SQLException {
Statement s1 = conn1.createStatement(), s2 = conn2.createStatement();
s1.execute("create local temporary table test(id int unique)");
s2.execute("create local temporary table test(id int unique)");
s1.execute("alter table test add constraint a unique(id)");
s2.execute("alter table test add constraint a unique(id)");
s1.execute("drop table test");
s2.execute("drop table test");
}
private void testIndexes(Connection conn1, Connection conn2) throws SQLException { private void testIndexes(Connection conn1, Connection conn2) throws SQLException {
conn1.createStatement().executeUpdate("create local temporary table test(id int)"); conn1.createStatement().executeUpdate("create local temporary table test(id int)");
conn1.createStatement().executeUpdate("create index idx_id on test(id)"); conn1.createStatement().executeUpdate("create index idx_id on test(id)");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论