提交 83705eb0 authored 作者: Thomas Mueller's avatar Thomas Mueller

IN(..): when combining and IN(..) condition with a condition that didn't use an…

IN(..): when combining and IN(..) condition with a condition that didn't use an index, the result could contain duplicate rows.
上级 d2f528bb
...@@ -19,7 +19,9 @@ Change Log ...@@ -19,7 +19,9 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>EXPLAIN: The query plan now contains ".tableScan" if a table scan is used. <ul><li>EXPLAIN: The query plan now contains ".tableScan" if a table scan is used.
</li><li>The index was not used if there were multiple IN(..) conditions. </li><li>IN(..): when combining and IN(..) condition with a condition that didn't use an index,
the result could contain duplicate rows.
</li><li>IN(..): the index was not used if there were multiple IN(..) conditions.
</li><li>For foreign key constraints, the metadata column </li><li>For foreign key constraints, the metadata column
INFORMATION_SCHEMA.INDEXES.CONSTRAINT_NAME was not set for non-unique indexes. INFORMATION_SCHEMA.INDEXES.CONSTRAINT_NAME was not set for non-unique indexes.
</li><li>PostgreSQL compatibility: when using the following exception was thrown: </li><li>PostgreSQL compatibility: when using the following exception was thrown:
......
...@@ -20,6 +20,7 @@ import org.h2.expression.ExpressionVisitor; ...@@ -20,6 +20,7 @@ import org.h2.expression.ExpressionVisitor;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.Table;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.value.CompareMode; import org.h2.value.CompareMode;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -219,28 +220,16 @@ public class IndexCondition { ...@@ -219,28 +220,16 @@ public class IndexCondition {
case Comparison.IN_LIST: case Comparison.IN_LIST:
case Comparison.IN_QUERY: case Comparison.IN_QUERY:
if (indexConditions.size() > 1) { if (indexConditions.size() > 1) {
// IN(..) can not be combined with other conditions. if (!column.getTable().getTableType().equals(Table.TABLE)) {
// If there are other conditions (except for other // if combined with other conditions,
// IN_ conditions), don't use the index on IN(..) // IN(..) can only be used for regular tables
// otherwise the query returns the wrong result. // test case:
boolean beforeThis = true; // create table test(a int, b int, primary key(id, name));
for (IndexCondition c : indexConditions) { // create unique index c on test(b, a);
if (c == this) { // insert into test values(1, 10), (2, 20);
beforeThis = false; // select * from (select * from test)
continue; // where a=1 and b in(10, 20);
} return 0;
if (c.isEvaluatable()) {
if (beforeThis) {
// If there are only multiple IN_ conditions,
// only the first one can be used
return 0;
}
if (!c.isIn()) {
// If there are other (non-IN_) conditions,
// this one can't be used
return 0;
}
}
} }
} }
return EQUALITY; return EQUALITY;
...@@ -264,16 +253,6 @@ public class IndexCondition { ...@@ -264,16 +253,6 @@ public class IndexCondition {
return compareType == Comparison.FALSE; return compareType == Comparison.FALSE;
} }
private boolean isIn() {
switch (compareType) {
case Comparison.IN_LIST:
case Comparison.IN_QUERY:
return true;
default:
return false;
}
}
/** /**
* Check if this index condition is of the type column larger or equal to * Check if this index condition is of the type column larger or equal to
* value. * value.
......
...@@ -249,7 +249,10 @@ public class PageDataIndex extends PageIndex { ...@@ -249,7 +249,10 @@ public class PageDataIndex extends PageIndex {
} }
public Cursor find(Session session, SearchRow first, SearchRow last) { public Cursor find(Session session, SearchRow first, SearchRow last) {
// ignore first and last if (first != null || last != null) {
// this index is a table scan, must not use it for lookup
throw DbException.throwInternalError(getSQL() + " " + first + " " + last);
}
PageData root = getPage(rootPageId, 0); PageData root = getPage(rootPageId, 0);
return root.find(session, Long.MIN_VALUE, Long.MAX_VALUE, isMultiVersion); return root.find(session, Long.MIN_VALUE, Long.MAX_VALUE, isMultiVersion);
} }
...@@ -422,9 +425,7 @@ public class PageDataIndex extends PageIndex { ...@@ -422,9 +425,7 @@ public class PageDataIndex extends PageIndex {
} }
public int getColumnIndex(Column col) { public int getColumnIndex(Column col) {
if (col.getColumnId() == mainIndexColumn) { // can not use this index - use the PageDelegateIndex instead
return 0;
}
return -1; return -1;
} }
......
...@@ -75,7 +75,10 @@ public class PageDelegateIndex extends PageIndex { ...@@ -75,7 +75,10 @@ public class PageDelegateIndex extends PageIndex {
} }
public int getColumnIndex(Column col) { public int getColumnIndex(Column col) {
return mainIndex.getColumnIndex(col); if (col.getColumnId() == mainIndex.getMainIndexColumn()) {
return 0;
}
return -1;
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks) {
......
...@@ -9,7 +9,6 @@ package org.h2.table; ...@@ -9,7 +9,6 @@ package org.h2.table;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
import org.h2.command.Parser; import org.h2.command.Parser;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.engine.Constants; import org.h2.engine.Constants;
......
--- special grammar and test cases --------------------------------------------------------------------------------------------- --- special grammar and test cases ---------------------------------------------------------------------------------------------
create table test(id int primary key, d int);
> ok
insert into test values(1,1), (2, 1);
> update count: 2
select id from test where id in (1, 2) and d = 1;
> ID
> --
> 1
> 2
> rows: 2
drop table test;
> ok
create table test(id decimal(10, 2) primary key) as select 0; create table test(id decimal(10, 2) primary key) as select 0;
> ok > ok
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论