提交 1e3e8ea3 authored 作者: Thomas Mueller's avatar Thomas Mueller

Fixed the Oracle mode: Oracle allows multiple rows only where all columns of the…

Fixed the Oracle mode: Oracle allows multiple rows only where all columns of the unique index are NULL. 
上级 741994ec
...@@ -80,6 +80,13 @@ public class Mode { ...@@ -80,6 +80,13 @@ public class Mode {
*/ */
public boolean uniqueIndexSingleNull; public boolean uniqueIndexSingleNull;
/**
* When using unique indexes, multiple rows with NULL in all columns
* are allowed, however it is not allowed to have multiple rows with the
* same values otherwise. This is how Oracle works.
*/
public boolean uniqueIndexSingleNullExceptAllColumnsAreNull;
/** /**
* If the syntax [OFFSET .. ROW] [FETCH ... ONLY] should be supported. * If the syntax [OFFSET .. ROW] [FETCH ... ONLY] should be supported.
* This is an alternative syntax for LIMIT .. OFFSET. * This is an alternative syntax for LIMIT .. OFFSET.
...@@ -121,6 +128,10 @@ public class Mode { ...@@ -121,6 +128,10 @@ public class Mode {
add(mode); add(mode);
mode = new Mode("Oracle"); mode = new Mode("Oracle");
mode.uniqueIndexSingleNullExceptAllColumnsAreNull = true;
add(mode);
mode = new Mode("DB2");
add(mode); add(mode);
} }
......
...@@ -11,6 +11,7 @@ import java.sql.SQLException; ...@@ -11,6 +11,7 @@ import java.sql.SQLException;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.DbObject; import org.h2.engine.DbObject;
import org.h2.engine.Mode;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.Message; import org.h2.message.Message;
import org.h2.message.Trace; import org.h2.message.Trace;
...@@ -248,8 +249,18 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index { ...@@ -248,8 +249,18 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
} }
public boolean containsNullAndAllowMultipleNull(Session session, Row newRow) { public boolean containsNullAndAllowMultipleNull(Session session, Row newRow) {
if (session.getDatabase().getMode().uniqueIndexSingleNull) { Mode mode = session.getDatabase().getMode();
if (mode.uniqueIndexSingleNull) {
return false; return false;
} else if (mode.uniqueIndexSingleNullExceptAllColumnsAreNull) {
for (int i = 0; i < columns.length; i++) {
int index = columnIds[i];
Value v = newRow.getValue(index);
if (v != ValueNull.INSTANCE) {
return false;
}
}
return true;
} }
for (int i = 0; i < columns.length; i++) { for (int i = 0; i < columns.length; i++) {
int index = columnIds[i]; int index = columnIds[i];
......
...@@ -25,6 +25,7 @@ public class TestCompatibility extends TestBase { ...@@ -25,6 +25,7 @@ public class TestCompatibility extends TestBase {
conn = getConnection("compatibility"); conn = getConnection("compatibility");
testUniqueIndexSingleNull(); testUniqueIndexSingleNull();
testUniqueIndexOracle();
testHsqlDb(); testHsqlDb();
testMySQL(); testMySQL();
...@@ -51,6 +52,30 @@ public class TestCompatibility extends TestBase { ...@@ -51,6 +52,30 @@ public class TestCompatibility extends TestBase {
} }
} }
private void testUniqueIndexOracle() throws Exception {
Statement stat = conn.createStatement();
stat.execute("SET MODE ORACLE");
stat.execute("create table t2(c1 int, c2 int)");
stat.execute("create unique index i2 on t2(c1, c2)");
stat.execute("insert into t2 values (null, 1)");
try {
stat.execute("insert into t2 values (null, 1)");
fail();
} catch (SQLException e) {
assertKnownException(e);
}
stat.execute("insert into t2 values (null, null)");
stat.execute("insert into t2 values (null, null)");
stat.execute("insert into t2 values (1, null)");
try {
stat.execute("insert into t2 values (1, null)");
fail();
} catch (SQLException e) {
assertKnownException(e);
}
stat.execute("DROP TABLE T2");
}
private void testHsqlDb() throws Exception { private void testHsqlDb() throws Exception {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("DROP TABLE TEST IF EXISTS; CREATE TABLE TEST(ID INT PRIMARY KEY); "); stat.execute("DROP TABLE TEST IF EXISTS; CREATE TABLE TEST(ID INT PRIMARY KEY); ");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论