提交 e1cdf544 authored 作者: sylvain-ilm's avatar sylvain-ilm

DROP TABLE RESTRICT shouldn't drop foreign constraints

上级 b5341bb5
......@@ -907,8 +907,8 @@ DROP SEQUENCE SEQ_ID
DROP TABLE [ IF EXISTS ] tableName [,...] [ RESTRICT | CASCADE ]
","
Drops an existing table, or a list of tables.
The command will fail if dependent views exist and the RESTRICT clause is used (the default).
All dependent views are dropped as well if the CASCADE clause is used.
The command will fail if dependent objects exist and the RESTRICT clause is used (the default).
All dependent views and constraints are dropped as well if the CASCADE clause is used.
This command commits an open transaction in this connection.
","
DROP TABLE TEST
......
......@@ -5,9 +5,12 @@
*/
package org.h2.command.ddl;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.h2.api.ErrorCode;
import org.h2.command.CommandInterface;
import org.h2.constraint.Constraint;
import org.h2.constraint.ConstraintReferential;
import org.h2.engine.Database;
import org.h2.engine.Right;
......@@ -73,15 +76,26 @@ public class DropTable extends SchemaCommand {
throw DbException.get(ErrorCode.CANNOT_DROP_TABLE_1, tableName);
}
if (dropAction == ConstraintReferential.RESTRICT) {
StatementBuilder buff = new StatementBuilder();
CopyOnWriteArrayList<TableView> dependentViews = table.getDependentViews();
if (dependentViews != null && dependentViews.size() > 0) {
StatementBuilder buff = new StatementBuilder();
for (TableView v : dependentViews) {
buff.appendExceptFirst(", ");
buff.append(v.getName());
}
throw DbException.get(ErrorCode.CANNOT_DROP_2, tableName, buff.toString());
}
final List<Constraint> constraints = table.getConstraints();
if (constraints != null && constraints.size() > 0) {
for (Constraint c : constraints) {
if (c.getTable() != table) {
buff.appendExceptFirst(", ");
buff.append(c.getName());
}
}
}
if (buff.length() > 0)
throw DbException.get(ErrorCode.CANNOT_DROP_2, tableName, buff.toString());
}
table.lock(session, true, true);
}
......
......@@ -54,6 +54,7 @@ public class TestCases extends TestBase {
testGroupSubquery();
testCountDistinctNotNull();
testDependencies();
testDropTable();
testConvertType();
testSortedSelect();
testMaxMemoryRows();
......@@ -278,6 +279,53 @@ public class TestCases extends TestBase {
conn.close();
}
private static enum DropDependent {
NONE, VIEW, FOREIGN_KEY;
}
private void testDropTable() throws SQLException {
trace("testDrop");
for (final boolean restrict : new boolean[] { true, false }) {
for (final DropDependent dropDep : DropDependent.values()) {
deleteDb("cases");
Connection conn = getConnection("cases");
Statement stat = conn.createStatement();
stat.execute("create table test(id int)");
if (dropDep == DropDependent.VIEW) {
stat.execute("create view abc as select * from test");
} else if (dropDep == DropDependent.FOREIGN_KEY) {
stat.execute("create table ref(id int, id_test int, foreign key (id_test) references test (id)) ");
// test table is empty so the foreign key forces ref table to be also empty
assertThrows(ErrorCode.REFERENTIAL_INTEGRITY_VIOLATED_PARENT_MISSING_1, stat).execute("insert into ref values(1,2)");
}
// drop allowed if no references or cascade
final boolean expectedDropSuccess = dropDep == DropDependent.NONE || !restrict;
assertThrows(expectedDropSuccess ? 0 : ErrorCode.CANNOT_DROP_2, stat).execute("drop table test " + (restrict ? "restrict" : "cascade"));
assertThrows(expectedDropSuccess ? ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 : 0, stat).execute("select * from test");
// missing view if it was never created or if the drop succeeded
assertThrows(dropDep != DropDependent.VIEW || expectedDropSuccess ? ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 : 0, stat).execute("select * from abc");
final int refError;
if (dropDep != DropDependent.FOREIGN_KEY) {
// never created
refError = ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1;
} else if (expectedDropSuccess) {
// foreign key dropped
refError = 0;
} else {
// foreign key not dropped
refError = ErrorCode.REFERENTIAL_INTEGRITY_VIOLATED_PARENT_MISSING_1;
}
assertThrows(refError, stat).execute("insert into ref values(1,2)");
conn.close();
}
}
}
private void testConvertType() throws SQLException {
deleteDb("cases");
Connection conn = getConnection("cases");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论