/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package my.test.command.ddl; import my.test.TestBase; public class AlterTableAddConstraintTest extends TestBase { public static void main(String[] args) throws Exception { new AlterTableAddConstraintTest().start(); } // 在eclipse中打断点条件table.getName().equalsIgnoreCase("mytable") @Override public void startInternal() throws Exception { executeUpdate("DROP TABLE IF EXISTS mytable"); executeUpdate("CREATE TABLE IF NOT EXISTS mytable (f1 int not null default 10, f2 int not null, f3 int, ch varchar(10))"); // ALTER_TABLE_ADD_CONSTRAINT_PRIMARY_KEY(); // ALTER_TABLE_ADD_CONSTRAINT_INDEX(); // ALTER_TABLE_ADD_CONSTRAINT_CHECK(); // ALTER_TABLE_ADD_CONSTRAINT_UNIQUE(); ALTER_TABLE_ADD_CONSTRAINT_REFERENTIAL(); } void ALTER_TABLE_ADD_CONSTRAINT_PRIMARY_KEY() throws Exception { executeUpdate("CREATE PRIMARY KEY HASH IF NOT EXISTS myindex ON mytable(f1, f2)"); // executeUpdate("CREATE INDEX IF NOT EXISTS myindex ON mytable(f1, f2)"); // 指定INDEX // myindex其实无用,见org.h2.command.ddl.AlterTableAddConstraint.tryUpdate()中 // 在ALTER_TABLE_ADD_CONSTRAINT_PRIMARY_KEY那的注释 sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c0 COMMENT IS 'haha0' PRIMARY KEY HASH(f1,f2) INDEX myindex"; executeUpdate(sql); executeUpdate("DROP INDEX IF EXISTS myindex"); sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c000 COMMENT IS 'haha0' PRIMARY KEY HASH(f1) INDEX myindex"; // executeUpdate(sql); // sql = // "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c0 COMMENT IS 'haha0' PRIMARY KEY HASH(f1)"; // sql = // "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c0 COMMENT IS 'haha0' PRIMARY KEY HASH(f2, f1)"; } void ALTER_TABLE_ADD_CONSTRAINT_INDEX() throws Exception { sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c1 COMMENT IS 'haha0' INDEX int"; executeUpdate(sql); sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c1 COMMENT IS 'haha0' INDEX myindex(f1,f2)"; executeUpdate(sql); } void ALTER_TABLE_ADD_CONSTRAINT_CHECK() throws Exception { sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c3 COMMENT IS 'haha3' CHECK f1>0 and f2<10 CHECK"; executeUpdate(sql); } void ALTER_TABLE_ADD_CONSTRAINT_UNIQUE() throws Exception { executeUpdate("DROP TABLE IF EXISTS mytable2"); executeUpdate("CREATE TABLE IF NOT EXISTS mytable2 (f1 int not null, f2 int not null)"); executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS idx0 ON mytable2(f1, f2)"); executeUpdate("CREATE INDEX IF NOT EXISTS idx1 ON mytable(f1, f2)"); executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS idx2 ON mytable(f1, f2, f3)"); executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS idx3 ON mytable(f2, f3)"); executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS idx4 ON mytable(f1, f2)"); executeUpdate("CREATE UNIQUE INDEX IF NOT EXISTS idx5 ON mytable(f1, f2)"); // idx0索引是mytable2表的,不是mytable,所以INDEX idx0无效,但是不报错 sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c4 UNIQUE KEY INDEX myunique(f1,f2) INDEX idx0 NOCHECK"; // idx1索引不是UNIQUE索引,所以INDEX idx1无效,但是不报错 sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c4 UNIQUE KEY INDEX myunique(f1,f2) INDEX idx1 NOCHECK"; // idx2是UNIQUE索引,但是它的索引字段是f1, f2, f3, 而这里只有f1, f2,所以INDEX idx2无效,但是不报错 sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c4 UNIQUE KEY INDEX myunique(f1,f2) INDEX idx2 NOCHECK"; // idx3是UNIQUE索引,索引字段个数与myunique一样, // 但是它的索引字段是f2, f3, 而这里是f1, f2,所以INDEX idx3无效,但是不报错 sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c4 UNIQUE KEY INDEX myunique(f1,f2) INDEX idx3 NOCHECK"; // idx4是正确的 sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c4 UNIQUE KEY INDEX myunique(f1,f2) INDEX idx4 NOCHECK"; // idx5也是正确的,因为idx5中的索引字段只有f1,f2,因为f1,f2保证唯一了,那么f1,f2,f3也是唯一的 sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c4 UNIQUE KEY INDEX myunique(f1,f2,f3) INDEX idx5 NOCHECK"; // 如果没有指定INDEX,则从已存在的唯一索引中选择一个合适的,如果没有合适的就自动创建一个 // 因为idx4满足了,所以使用idx4 sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c4 UNIQUE KEY INDEX myunique(f1,f2) NOCHECK"; // 不存在满足f1,f3的唯一索引,所以要自动创建一个 sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c4 UNIQUE KEY INDEX myunique(f1,f3) NOCHECK"; executeUpdate(sql); // 因为此时idx4己属于myunique2约束,所以不能删除idx4索引 sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c5 UNIQUE KEY INDEX myunique2(f1,f2) INDEX idx4 NOCHECK"; executeUpdate(sql); // 抛异常: Index "IDX4" belongs to a constraint; SQL statement: DROP INDEX // IF EXISTS idx4 [90085-171] tryExecuteUpdate("DROP INDEX IF EXISTS idx4"); } void ALTER_TABLE_ADD_CONSTRAINT_REFERENTIAL() throws Exception { executeUpdate("DROP TABLE IF EXISTS mytable"); executeUpdate("CREATE TABLE IF NOT EXISTS mytable (f1 int default 10, f2 int not null, f3 int, ch varchar(10))"); executeUpdate("DROP TABLE IF EXISTS mytable2"); executeUpdate("CREATE TABLE IF NOT EXISTS mytable2 (f1 int PRIMARY KEY, f2 int not null)"); executeUpdate("DROP TABLE IF EXISTS mytable3"); executeUpdate("CREATE TABLE IF NOT EXISTS mytable3 (f1 int, f2 int not null)"); // 如果未指定引用列,则默认使用引用表中的主键列,这里会默认使用mytable2的f1字段,因为f1是PRIMARY KEY sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c0 FOREIGN KEY(f1) REFERENCES mytable2"; executeUpdate(sql); // 如果引用表没有PRIMARY KEY,则抛异常: // Exception in thread "main" org.h2.jdbc.JdbcSQLException: Index // "PRIMARY_KEY_" not found; SQL statement: // ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c0 FOREIGN KEY(f1) // REFERENCES mytable3 [42112-171] sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c1 FOREIGN KEY(f1) REFERENCES mytable3"; tryExecuteUpdate(sql); // 外部列与引用列的个数不一样时,也抛错: org.h2.jdbc.JdbcSQLException: Column count does // not match; sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c0 FOREIGN KEY(f1, f2) REFERENCES mytable2"; sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c0 FOREIGN KEY(f1) REFERENCES mytable2 CHECK"; sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c0 FOREIGN KEY(f1) REFERENCES mytable2 ON DELETE CASCADE CHECK"; sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c0 FOREIGN KEY(f1) REFERENCES mytable2 ON DELETE SET DEFAULT CHECK"; sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c0 FOREIGN KEY(f1) REFERENCES mytable2 ON UPDATE CASCADE CHECK"; sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c3 FOREIGN KEY(f1) REFERENCES mytable2 ON UPDATE SET DEFAULT CHECK"; // sql = // "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c3 FOREIGN KEY(f1) REFERENCES mytable2 ON UPDATE RESTRICT"; // sql = // "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c0 FOREIGN KEY(f1) REFERENCES(f2)"; sql = "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c4 FOREIGN KEY(f1) REFERENCES mytable2 ON UPDATE SET DEFAULT ON DELETE CASCADE"; executeUpdate(sql); executeUpdate("SET REFERENTIAL_INTEGRITY 0"); executeUpdate("insert into mytable2(f1, f2) values(1,1)"); executeUpdate("SET REFERENTIAL_INTEGRITY 1"); executeUpdate("ALTER TABLE mytable2 SET REFERENTIAL_INTEGRITY FALSE"); executeUpdate("insert into mytable2(f1, f2) values(2,2)"); executeUpdate("ALTER TABLE mytable2 SET REFERENTIAL_INTEGRITY TRUE CHECK"); executeUpdate("insert into mytable2(f1, f2) values(3,3)"); executeUpdate("insert into mytable(f1, f2) values(2,2)"); executeUpdate("insert into mytable(f1, f2) values(3,3)"); // 注意: 为引用字段建立了唯一索引,所以f2是三时,如果是自引用,就抛异常 // executeUpdate("insert into mytable(f1, f2) values(2,3)"); executeUpdate("insert into mytable(f1, f2) values(2,4)"); // Referential integrity constraint violation tryExecuteUpdate("update mytable set f1=20 where f1=2"); executeUpdate("insert into mytable(f1, f2) values(null,2)"); executeUpdate("update mytable set f1=null where f1=2"); executeUpdate("update mytable set f2=30 where f1=3"); executeUpdate("delete from mytable where f1 = 2"); // executeUpdate("update mytable2 set f2=10 where f1=1"); // 如果是ON UPDATE RESTRICT,当更新引用表的记录在外部表中存在时不允许更新 // 比如此列f1是2,在mytable中存在,所以不允许更新 // 如果是ON UPDATE SET DEFAULT,可以为mytable的f1指定一个默认值,比如10, // 虽然10不出现在mytable2中,但这是允许的 executeUpdate("update mytable2 set f1=20 where f1=2"); executeUpdate("update mytable2 set f2=30 where f1=3"); sql = "select * from mytable"; executeQuery(); // 这是允许的,因为在mytable中不存在3 // executeUpdate("update mytable2 set f1=30 where f1=3"); // // sql = // "ALTER TABLE mytable ADD CONSTRAINT IF NOT EXISTS c6 COMMENT IS 'haha6' FOREIGN KEY(f1) REFERENCES mytable(f2)" // + // "ON DELETE CASCADE ON UPDATE RESTRICT ON DELETE NO ACTION ON UPDATE SET NULL ON DELETE SET DEFAULT NOT DEFERRABLE"; } }