提交 fd3ad0ae authored 作者: Thomas Mueller's avatar Thomas Mueller

Referenced objects in check constraints could be dropped, which resulted in a…

Referenced objects in check constraints could be dropped, which resulted in a database that can't be opened normally.
上级 42edd760
...@@ -9,6 +9,7 @@ package org.h2.constraint; ...@@ -9,6 +9,7 @@ package org.h2.constraint;
import java.util.HashSet; import java.util.HashSet;
import org.h2.engine.DbObject; import org.h2.engine.DbObject;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.ExpressionVisitor;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.message.Trace; import org.h2.message.Trace;
...@@ -179,4 +180,15 @@ public abstract class Constraint extends SchemaObjectBase implements Comparable< ...@@ -179,4 +180,15 @@ public abstract class Constraint extends SchemaObjectBase implements Comparable<
return table.isHidden(); return table.isHidden();
} }
/**
* Visit all elements in the constraint.
*
* @param visitor the visitor
* @return true if every visited expression returned true, or if there are
* no expressions
*/
public boolean isEverything(ExpressionVisitor visitor) {
return true;
}
} }
...@@ -140,4 +140,8 @@ public class ConstraintCheck extends Constraint { ...@@ -140,4 +140,8 @@ public class ConstraintCheck extends Constraint {
// nothing to do // nothing to do
} }
public boolean isEverything(ExpressionVisitor visitor) {
return expr.isEverything(visitor);
}
} }
...@@ -311,6 +311,10 @@ public abstract class Table extends SchemaObjectBase { ...@@ -311,6 +311,10 @@ public abstract class Table extends SchemaObjectBase {
* @param dependencies the current set of dependencies * @param dependencies the current set of dependencies
*/ */
public void addDependencies(HashSet<DbObject> dependencies) { public void addDependencies(HashSet<DbObject> dependencies) {
if (dependencies.contains(this)) {
// avoid endless recursion
return;
}
if (sequences != null) { if (sequences != null) {
for (Sequence s : sequences) { for (Sequence s : sequences) {
dependencies.add(s); dependencies.add(s);
...@@ -320,6 +324,12 @@ public abstract class Table extends SchemaObjectBase { ...@@ -320,6 +324,12 @@ public abstract class Table extends SchemaObjectBase {
for (Column col : columns) { for (Column col : columns) {
col.isEverything(visitor); col.isEverything(visitor);
} }
if (constraints != null) {
for (Constraint c : constraints) {
c.isEverything(visitor);
}
}
dependencies.add(this);
} }
public ArrayList<DbObject> getChildren() { public ArrayList<DbObject> getChildren() {
......
...@@ -37,6 +37,7 @@ public class TestCases extends TestBase { ...@@ -37,6 +37,7 @@ public class TestCases extends TestBase {
} }
public void test() throws Exception { public void test() throws Exception {
testDependencies();
testConvertType(); testConvertType();
testSortedSelect(); testSortedSelect();
testMaxMemoryRowsDistinct(); testMaxMemoryRowsDistinct();
...@@ -92,6 +93,43 @@ public class TestCases extends TestBase { ...@@ -92,6 +93,43 @@ public class TestCases extends TestBase {
deleteDb("cases"); deleteDb("cases");
} }
private void testDependencies() throws SQLException {
deleteDb("cases");
Connection conn = getConnection("cases");
Statement stat = conn.createStatement();
// avoid endless recursion when adding dependencies
stat.execute("create table test(id int primary key, parent int)");
stat.execute("alter table test add constraint test check (select count(*) from test) < 10");
stat.execute("create table b()");
stat.execute("drop table b");
stat.execute("drop table test");
// ensure the dependency is detected
stat.execute("create alias is_positive as 'boolean isPositive(int x) { return x > 0; }'");
stat.execute("create table a(a integer, constraint test check is_positive(a))");
try {
stat.execute("drop alias is_positive");
fail();
} catch (SQLException e) {
assertEquals(ErrorCode.CANNOT_DROP_2, e.getErrorCode());
}
stat.execute("drop table a");
stat.execute("drop alias is_positive");
// ensure trying to reference the table fails
// (otherwise re-opening the database is not possible)
stat.execute("create table test(id int primary key)");
try {
stat.execute("alter table test alter column id set default ifnull((select max(id) from test for update)+1, 0)");
fail();
} catch (SQLException e) {
assertEquals(ErrorCode.COLUMN_IS_REFERENCED_1, e.getErrorCode());
}
stat.execute("drop table test");
conn.close();
}
private void testConvertType() throws SQLException { private void testConvertType() throws SQLException {
deleteDb("cases"); deleteDb("cases");
Connection conn = getConnection("cases"); Connection conn = getConnection("cases");
...@@ -101,6 +139,7 @@ public class TestCases extends TestBase { ...@@ -101,6 +139,7 @@ public class TestCases extends TestBase {
assertEquals(2, meta.getPrecision(1)); assertEquals(2, meta.getPrecision(1));
assertEquals(2, meta.getScale(1)); assertEquals(2, meta.getScale(1));
stat.execute("alter table test add column y int"); stat.execute("alter table test add column y int");
stat.execute("drop table test");
conn.close(); conn.close();
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论