提交 99bb9cda authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Fix NULL handling in UNIQUE HASH indexes

上级 daf543c5
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*/ */
package org.h2.index; package org.h2.index;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
...@@ -20,6 +21,7 @@ import org.h2.table.RegularTable; ...@@ -20,6 +21,7 @@ import org.h2.table.RegularTable;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueNull;
/** /**
* An unique index based on an in-memory hash map. * An unique index based on an in-memory hash map.
...@@ -33,6 +35,7 @@ public class HashIndex extends BaseIndex { ...@@ -33,6 +35,7 @@ public class HashIndex extends BaseIndex {
private final boolean totalOrdering; private final boolean totalOrdering;
private final RegularTable tableData; private final RegularTable tableData;
private Map<Value, Long> rows; private Map<Value, Long> rows;
private final ArrayList<Long> nullRows = new ArrayList<>();
public HashIndex(RegularTable table, int id, String indexName, IndexColumn[] columns, IndexType indexType) { public HashIndex(RegularTable table, int id, String indexName, IndexColumn[] columns, IndexType indexType) {
super(table, id, indexName, columns, indexType); super(table, id, indexName, columns, indexType);
...@@ -55,17 +58,26 @@ public class HashIndex extends BaseIndex { ...@@ -55,17 +58,26 @@ public class HashIndex extends BaseIndex {
@Override @Override
public void add(Session session, Row row) { public void add(Session session, Row row) {
Value key = row.getValue(indexColumn); Value key = row.getValue(indexColumn);
if (key != ValueNull.INSTANCE) {
Object old = rows.get(key); Object old = rows.get(key);
if (old != null) { if (old != null) {
// TODO index duplicate key for hash indexes: is this allowed? // TODO index duplicate key for hash indexes: is this allowed?
throw getDuplicateKeyException(key.toString()); throw getDuplicateKeyException(key.toString());
} }
rows.put(key, row.getKey()); rows.put(key, row.getKey());
} else {
nullRows.add(row.getKey());
}
} }
@Override @Override
public void remove(Session session, Row row) { public void remove(Session session, Row row) {
rows.remove(row.getValue(indexColumn)); Value key = row.getValue(indexColumn);
if (key != ValueNull.INSTANCE) {
rows.remove(key);
} else {
nullRows.remove(row.getKey());
}
} }
@Override @Override
...@@ -75,6 +87,9 @@ public class HashIndex extends BaseIndex { ...@@ -75,6 +87,9 @@ public class HashIndex extends BaseIndex {
throw DbException.throwInternalError(first + " " + last); throw DbException.throwInternalError(first + " " + last);
} }
Value v = first.getValue(indexColumn); Value v = first.getValue(indexColumn);
if (v == ValueNull.INSTANCE) {
return new NonUniqueHashCursor(session, tableData, nullRows);
}
/* /*
* Sometimes the incoming search is a similar, but not the same type * Sometimes the incoming search is a similar, but not the same type
* e.g. the search value is INT, but the index column is LONG. In which * e.g. the search value is INT, but the index column is LONG. In which
...@@ -94,12 +109,12 @@ public class HashIndex extends BaseIndex { ...@@ -94,12 +109,12 @@ public class HashIndex extends BaseIndex {
@Override @Override
public long getRowCount(Session session) { public long getRowCount(Session session) {
return rows.size(); return getRowCountApproximation();
} }
@Override @Override
public long getRowCountApproximation() { public long getRowCountApproximation() {
return rows.size(); return rows.size() + nullRows.size();
} }
@Override @Override
......
...@@ -87,5 +87,21 @@ CREATE UNIQUE HASH INDEX TEST_IDX ON TEST(N); ...@@ -87,5 +87,21 @@ CREATE UNIQUE HASH INDEX TEST_IDX ON TEST(N);
SELECT 1 FROM TEST WHERE N = 0; SELECT 1 FROM TEST WHERE N = 0;
>> 1 >> 1
INSERT INTO TEST VALUES (NULL);
> update count: 1
SELECT N FROM TEST WHERE N IS NULL;
> N
> ----
> null
> null
> rows: 2
DELETE FROM TEST WHERE N IS NULL LIMIT 1;
> update count: 1
SELECT N FROM TEST WHERE N IS NULL;
>> null
DROP TABLE TEST; DROP TABLE TEST;
> ok > ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论