Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
6cdd1755
提交
6cdd1755
authored
8月 31, 2015
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #168 from svladykin/compareValuesTest
Test for TableEngines with wrong compareRows
上级
232d49d4
a02651c7
隐藏空白字符变更
内嵌
并排
正在显示
1 个修改的文件
包含
624 行增加
和
4 行删除
+624
-4
TestTableEngines.java
h2/src/test/org/h2/test/db/TestTableEngines.java
+624
-4
没有找到文件。
h2/src/test/org/h2/test/db/TestTableEngines.java
浏览文件 @
6cdd1755
...
@@ -6,12 +6,21 @@
...
@@ -6,12 +6,21 @@
package
org
.
h2
.
test
.
db
;
package
org
.
h2
.
test
.
db
;
import
java.sql.Connection
;
import
java.sql.Connection
;
import
java.sql.PreparedStatement
;
import
java.sql.ResultSet
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
java.sql.Statement
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.Set
;
import
java.util.TreeSet
;
import
org.h2.api.TableEngine
;
import
org.h2.api.TableEngine
;
import
org.h2.command.ddl.CreateTableData
;
import
org.h2.command.ddl.CreateTableData
;
import
org.h2.engine.Constants
;
import
org.h2.engine.Session
;
import
org.h2.engine.Session
;
import
org.h2.expression.Expression
;
import
org.h2.expression.Expression
;
import
org.h2.index.BaseIndex
;
import
org.h2.index.BaseIndex
;
...
@@ -19,6 +28,7 @@ import org.h2.index.Cursor;
...
@@ -19,6 +28,7 @@ import org.h2.index.Cursor;
import
org.h2.index.Index
;
import
org.h2.index.Index
;
import
org.h2.index.IndexType
;
import
org.h2.index.IndexType
;
import
org.h2.index.SingleRowCursor
;
import
org.h2.index.SingleRowCursor
;
import
org.h2.message.DbException
;
import
org.h2.result.Row
;
import
org.h2.result.Row
;
import
org.h2.result.SearchRow
;
import
org.h2.result.SearchRow
;
import
org.h2.result.SortOrder
;
import
org.h2.result.SortOrder
;
...
@@ -27,6 +37,7 @@ import org.h2.table.Table;
...
@@ -27,6 +37,7 @@ import org.h2.table.Table;
import
org.h2.table.TableBase
;
import
org.h2.table.TableBase
;
import
org.h2.table.TableFilter
;
import
org.h2.table.TableFilter
;
import
org.h2.test.TestBase
;
import
org.h2.test.TestBase
;
import
org.h2.util.New
;
import
org.h2.value.Value
;
import
org.h2.value.Value
;
import
org.h2.value.ValueInt
;
import
org.h2.value.ValueInt
;
import
org.h2.value.ValueNull
;
import
org.h2.value.ValueNull
;
...
@@ -50,12 +61,10 @@ public class TestTableEngines extends TestBase {
...
@@ -50,12 +61,10 @@ public class TestTableEngines extends TestBase {
@Override
@Override
public
void
test
()
throws
Exception
{
public
void
test
()
throws
Exception
{
if
(
config
.
mvcc
)
{
return
;
}
testEarlyFilter
();
testEarlyFilter
();
testEngineParams
();
testEngineParams
();
testSimpleQuery
();
testSimpleQuery
();
testMultiColumnTreeSetIndex
();
}
}
private
void
testEarlyFilter
()
throws
SQLException
{
private
void
testEarlyFilter
()
throws
SQLException
{
...
@@ -156,6 +165,244 @@ public class TestTableEngines extends TestBase {
...
@@ -156,6 +165,244 @@ public class TestTableEngines extends TestBase {
rs
.
close
();
rs
.
close
();
}
}
private
void
testMultiColumnTreeSetIndex
()
throws
SQLException
{
deleteDb
(
"tableEngine"
);
Connection
conn
=
getConnection
(
"tableEngine"
);
Statement
stat
=
conn
.
createStatement
();
stat
.
executeUpdate
(
"CREATE TABLE T(A INT, B VARCHAR, C BIGINT) ENGINE \""
+
TreeSetIndexTableEngine
.
class
.
getName
()
+
"\""
);
stat
.
executeUpdate
(
"CREATE INDEX IDX_CBA ON T(C, B, A)"
);
stat
.
executeUpdate
(
"CREATE INDEX IDX_BA ON T(B, A)"
);
List
<
List
<
Object
>>
dataSet
=
New
.
arrayList
();
dataSet
.
add
(
Arrays
.<
Object
>
asList
(
1
,
"1"
,
1L
));
dataSet
.
add
(
Arrays
.<
Object
>
asList
(
1
,
"0"
,
2L
));
dataSet
.
add
(
Arrays
.<
Object
>
asList
(
2
,
"0"
,
-
1L
));
dataSet
.
add
(
Arrays
.<
Object
>
asList
(
0
,
"0"
,
1L
));
dataSet
.
add
(
Arrays
.<
Object
>
asList
(
0
,
"1"
,
null
));
dataSet
.
add
(
Arrays
.<
Object
>
asList
(
2
,
null
,
0L
));
PreparedStatement
prep
=
conn
.
prepareStatement
(
"INSERT INTO T VALUES(?,?,?)"
);
for
(
List
<
Object
>
row
:
dataSet
)
{
for
(
int
i
=
0
;
i
<
row
.
size
();
i
++)
{
prep
.
setObject
(
i
+
1
,
row
.
get
(
i
));
}
assertEquals
(
1
,
prep
.
executeUpdate
());
}
prep
.
close
();
checkPlan
(
stat
,
"select max(c) from t"
,
"direct lookup"
);
checkPlan
(
stat
,
"select min(c) from t"
,
"direct lookup"
);
checkPlan
(
stat
,
"select count(*) from t"
,
"direct lookup"
);
checkPlan
(
stat
,
"select * from t"
,
"scan"
);
checkPlan
(
stat
,
"select * from t order by c"
,
"IDX_CBA"
);
checkPlan
(
stat
,
"select * from t order by c, b"
,
"IDX_CBA"
);
checkPlan
(
stat
,
"select * from t order by b"
,
"IDX_BA"
);
checkPlan
(
stat
,
"select * from t order by b, a"
,
"IDX_BA"
);
checkPlan
(
stat
,
"select * from t order by b, c"
,
"scan"
);
checkPlan
(
stat
,
"select * from t order by a, b"
,
"scan"
);
checkPlan
(
stat
,
"select * from t order by a, c, b"
,
"scan"
);
checkPlan
(
stat
,
"select * from t where b > ''"
,
"IDX_BA"
);
checkPlan
(
stat
,
"select * from t where a > 0 and b > ''"
,
"IDX_BA"
);
checkPlan
(
stat
,
"select * from t where b < ''"
,
"IDX_BA"
);
checkPlan
(
stat
,
"select * from t where b < '' and c < 1"
,
"IDX_CBA"
);
checkPlan
(
stat
,
"select * from t where a = 0"
,
"scan"
);
checkPlan
(
stat
,
"select * from t where a > 0 order by c, b"
,
"IDX_CBA"
);
checkPlan
(
stat
,
"select * from t where a = 0 and c > 0"
,
"IDX_CBA"
);
checkPlan
(
stat
,
"select * from t where a = 0 and b < 0"
,
"IDX_BA"
);
assertEquals
(
6
,
((
Number
)
query
(
stat
,
"select count(*) from t"
).
get
(
0
).
get
(
0
)).
intValue
());
checkResultsNoOrder
(
stat
,
6
,
"select * from t"
,
"select * from t order by a"
);
checkResultsNoOrder
(
stat
,
6
,
"select * from t"
,
"select * from t order by b"
);
checkResultsNoOrder
(
stat
,
6
,
"select * from t"
,
"select * from t order by c"
);
checkResultsNoOrder
(
stat
,
6
,
"select * from t"
,
"select * from t order by c, a"
);
checkResultsNoOrder
(
stat
,
6
,
"select * from t"
,
"select * from t order by b, a"
);
checkResultsNoOrder
(
stat
,
6
,
"select * from t"
,
"select * from t order by c, b, a"
);
checkResultsNoOrder
(
stat
,
6
,
"select * from t"
,
"select * from t order by a, c, b"
);
checkResultsNoOrder
(
stat
,
4
,
"select * from t where a > 0"
,
"select * from t where a > 0 order by a"
);
checkResultsNoOrder
(
stat
,
4
,
"select * from t where a > 0"
,
"select * from t where a > 0 order by b"
);
checkResultsNoOrder
(
stat
,
4
,
"select * from t where a > 0"
,
"select * from t where a > 0 order by c"
);
checkResultsNoOrder
(
stat
,
4
,
"select * from t where a > 0"
,
"select * from t where a > 0 order by c, a"
);
checkResultsNoOrder
(
stat
,
4
,
"select * from t where a > 0"
,
"select * from t where a > 0 order by b, a"
);
checkResultsNoOrder
(
stat
,
4
,
"select * from t where a > 0"
,
"select * from t where a > 0 order by c, b, a"
);
checkResultsNoOrder
(
stat
,
4
,
"select * from t where a > 0"
,
"select * from t where a > 0 order by a, c, b"
);
checkResults
(
6
,
dataSet
,
stat
,
"select * from t order by a"
,
null
,
new
RowComparator
(
0
));
checkResults
(
6
,
dataSet
,
stat
,
"select * from t order by b, c"
,
null
,
new
RowComparator
(
1
,
2
));
checkResults
(
6
,
dataSet
,
stat
,
"select * from t order by c, a"
,
null
,
new
RowComparator
(
2
,
0
));
checkResults
(
6
,
dataSet
,
stat
,
"select * from t order by b, a"
,
null
,
new
RowComparator
(
1
,
0
));
checkResults
(
6
,
dataSet
,
stat
,
"select * from t order by c, b, a"
,
null
,
new
RowComparator
(
2
,
1
,
0
));
checkResults
(
4
,
dataSet
,
stat
,
"select * from t where a > 0"
,
new
RowFilter
()
{
@Override
protected
boolean
accept
(
List
<
Object
>
row
)
{
return
getInt
(
row
,
0
)
>
0
;
}
},
null
);
checkResults
(
3
,
dataSet
,
stat
,
"select * from t where b = '0'"
,
new
RowFilter
()
{
@Override
protected
boolean
accept
(
List
<
Object
>
row
)
{
return
"0"
.
equals
(
getString
(
row
,
1
));
}
},
null
);
checkResults
(
5
,
dataSet
,
stat
,
"select * from t where b >= '0'"
,
new
RowFilter
()
{
@Override
protected
boolean
accept
(
List
<
Object
>
row
)
{
String
b
=
getString
(
row
,
1
);
return
b
!=
null
&&
b
.
compareTo
(
"0"
)
>=
0
;
}
},
null
);
checkResults
(
2
,
dataSet
,
stat
,
"select * from t where b > '0'"
,
new
RowFilter
()
{
@Override
protected
boolean
accept
(
List
<
Object
>
row
)
{
String
b
=
getString
(
row
,
1
);
return
b
!=
null
&&
b
.
compareTo
(
"0"
)
>
0
;
}
},
null
);
checkResults
(
1
,
dataSet
,
stat
,
"select * from t where b > '0' and c > 0"
,
new
RowFilter
()
{
@Override
protected
boolean
accept
(
List
<
Object
>
row
)
{
String
b
=
getString
(
row
,
1
);
Long
c
=
getLong
(
row
,
2
);
return
b
!=
null
&&
b
.
compareTo
(
"0"
)
>
0
&&
c
!=
null
&&
c
>
0
;
}
},
null
);
checkResults
(
1
,
dataSet
,
stat
,
"select * from t where b > '0' and c < 2"
,
new
RowFilter
()
{
@Override
protected
boolean
accept
(
List
<
Object
>
row
)
{
String
b
=
getString
(
row
,
1
);
Long
c
=
getLong
(
row
,
2
);
return
b
!=
null
&&
b
.
compareTo
(
"0"
)
>
0
&&
c
!=
null
&&
c
<
2
;
}
},
null
);
checkResults
(
2
,
dataSet
,
stat
,
"select * from t where b > '0' and a < 2"
,
new
RowFilter
()
{
@Override
protected
boolean
accept
(
List
<
Object
>
row
)
{
Integer
a
=
getInt
(
row
,
0
);
String
b
=
getString
(
row
,
1
);
return
b
!=
null
&&
b
.
compareTo
(
"0"
)
>
0
&&
a
!=
null
&&
a
<
2
;
}
},
null
);
checkResults
(
1
,
dataSet
,
stat
,
"select * from t where b > '0' and a > 0"
,
new
RowFilter
()
{
@Override
protected
boolean
accept
(
List
<
Object
>
row
)
{
Integer
a
=
getInt
(
row
,
0
);
String
b
=
getString
(
row
,
1
);
return
b
!=
null
&&
b
.
compareTo
(
"0"
)
>
0
&&
a
!=
null
&&
a
>
0
;
}
},
null
);
checkResults
(
2
,
dataSet
,
stat
,
"select * from t where b = '0' and a > 0"
,
new
RowFilter
()
{
@Override
protected
boolean
accept
(
List
<
Object
>
row
)
{
Integer
a
=
getInt
(
row
,
0
);
String
b
=
getString
(
row
,
1
);
return
"0"
.
equals
(
b
)
&&
a
!=
null
&&
a
>
0
;
}
},
null
);
checkResults
(
2
,
dataSet
,
stat
,
"select * from t where b = '0' and a < 2"
,
new
RowFilter
()
{
@Override
protected
boolean
accept
(
List
<
Object
>
row
)
{
Integer
a
=
getInt
(
row
,
0
);
String
b
=
getString
(
row
,
1
);
return
"0"
.
equals
(
b
)
&&
a
!=
null
&&
a
<
2
;
}
},
null
);
deleteDb
(
"tableEngine"
);
}
private
void
checkResultsNoOrder
(
Statement
stat
,
int
size
,
String
qry1
,
String
qry2
)
throws
SQLException
{
List
<
List
<
Object
>>
res1
=
query
(
stat
,
qry1
);
List
<
List
<
Object
>>
res2
=
query
(
stat
,
qry2
);
if
(
size
!=
res1
.
size
()
||
size
!=
res2
.
size
())
{
fail
(
"Wrong size: \n"
+
res1
+
"\n"
+
res2
);
}
if
(
size
==
0
)
{
return
;
}
int
[]
cols
=
new
int
[
res1
.
get
(
0
).
size
()];
for
(
int
i
=
0
;
i
<
cols
.
length
;
i
++)
{
cols
[
i
]
=
i
;
}
Comparator
<
List
<
Object
>>
cmp
=
new
RowComparator
(
cols
);
Collections
.
sort
(
res1
,
cmp
);
Collections
.
sort
(
res2
,
cmp
);
assertTrue
(
"Wrong data: \n"
+
res1
+
"\n"
+
res2
,
res1
.
equals
(
res2
));
}
private
void
checkResults
(
int
size
,
List
<
List
<
Object
>>
dataSet
,
Statement
stat
,
String
qry
,
RowFilter
filter
,
RowComparator
sort
)
throws
SQLException
{
List
<
List
<
Object
>>
res1
=
query
(
stat
,
qry
);
List
<
List
<
Object
>>
res2
=
query
(
dataSet
,
filter
,
sort
);
assertTrue
(
"Wrong size: "
+
size
+
" \n"
+
res1
+
"\n"
+
res2
,
res1
.
size
()
==
size
&&
res2
.
size
()
==
size
);
assertTrue
(
filter
!=
null
||
sort
!=
null
);
for
(
int
i
=
0
;
i
<
res1
.
size
();
i
++)
{
List
<
Object
>
row1
=
res1
.
get
(
i
);
List
<
Object
>
row2
=
res2
.
get
(
i
);
assertTrue
(
"Filter failed on row "
+
i
+
" of \n"
+
res1
+
"\n"
+
res2
,
filter
==
null
||
filter
.
accept
(
row1
));
assertTrue
(
"Sort failed on row "
+
i
+
" of \n"
+
res1
+
"\n"
+
res2
,
sort
==
null
||
sort
.
compare
(
row1
,
row2
)
==
0
);
}
}
private
List
<
List
<
Object
>>
query
(
List
<
List
<
Object
>>
dataSet
,
RowFilter
filter
,
RowComparator
sort
)
{
List
<
List
<
Object
>>
res
=
New
.
arrayList
();
if
(
filter
==
null
)
{
res
.
addAll
(
dataSet
);
}
else
{
for
(
List
<
Object
>
row
:
dataSet
)
{
if
(
filter
.
accept
(
row
))
{
res
.
add
(
row
);
}
}
}
if
(
sort
!=
null
)
{
Collections
.
sort
(
res
,
sort
);
}
return
res
;
}
private
List
<
List
<
Object
>>
query
(
Statement
stat
,
String
qry
)
throws
SQLException
{
ResultSet
rs
=
stat
.
executeQuery
(
qry
);
int
cols
=
rs
.
getMetaData
().
getColumnCount
();
List
<
List
<
Object
>>
list
=
New
.
arrayList
();
while
(
rs
.
next
())
{
List
<
Object
>
row
=
New
.
arrayList
(
cols
);
for
(
int
i
=
1
;
i
<=
cols
;
i
++)
{
row
.
add
(
rs
.
getObject
(
i
));
}
list
.
add
(
row
);
}
rs
.
close
();
return
list
;
}
private
void
checkPlan
(
Statement
stat
,
String
qry
,
String
index
)
throws
SQLException
{
String
plan
=
query
(
stat
,
"EXPLAIN "
+
qry
).
get
(
0
).
get
(
0
).
toString
();
assertTrue
(
"Index '"
+
index
+
"' is not used in query plan: "
+
plan
,
plan
.
contains
(
index
));
}
/**
/**
* A test table factory.
* A test table factory.
...
@@ -448,5 +695,378 @@ public class TestTableEngines extends TestBase {
...
@@ -448,5 +695,378 @@ public class TestTableEngines extends TestBase {
}
}
}
}
/**
*/
public
static
class
TreeSetIndexTableEngine
implements
TableEngine
{
@Override
public
Table
createTable
(
CreateTableData
data
)
{
return
new
TreeSetTable
(
data
);
}
}
/**
*/
private
static
class
TreeSetTable
extends
TableBase
{
int
dataMoficationId
;
ArrayList
<
Index
>
indexes
;
TreeSetIndex
scan
=
new
TreeSetIndex
(
this
,
"scan"
,
IndexColumn
.
wrap
(
getColumns
()),
IndexType
.
createScan
(
false
))
{
@Override
public
double
getCost
(
Session
session
,
int
[]
masks
,
TableFilter
filter
,
SortOrder
sortOrder
)
{
return
getRowCount
(
session
)
+
Constants
.
COST_ROW_OFFSET
;
}
};
public
TreeSetTable
(
CreateTableData
data
)
{
super
(
data
);
}
@Override
public
void
checkRename
()
{
// No-op.
}
@Override
public
void
unlock
(
Session
s
)
{
// No-op.
}
@Override
public
void
truncate
(
Session
session
)
{
if
(
indexes
!=
null
)
{
for
(
Index
index
:
indexes
)
{
index
.
truncate
(
session
);
}
}
else
{
scan
.
truncate
(
session
);
}
dataMoficationId
++;
}
@Override
public
void
removeRow
(
Session
session
,
Row
row
)
{
if
(
indexes
!=
null
)
{
for
(
Index
index
:
indexes
)
{
index
.
remove
(
session
,
row
);
}
}
else
{
scan
.
remove
(
session
,
row
);
}
dataMoficationId
++;
}
@Override
public
void
addRow
(
Session
session
,
Row
row
)
{
if
(
indexes
!=
null
)
{
for
(
Index
index
:
indexes
)
{
index
.
add
(
session
,
row
);
}
}
else
{
scan
.
add
(
session
,
row
);
}
dataMoficationId
++;
}
@Override
public
Index
addIndex
(
Session
session
,
String
indexName
,
int
indexId
,
IndexColumn
[]
cols
,
IndexType
indexType
,
boolean
create
,
String
indexComment
)
{
if
(
indexes
==
null
)
{
indexes
=
New
.
arrayList
(
2
);
// Scan must be always at 0.
indexes
.
add
(
scan
);
}
Index
index
=
new
TreeSetIndex
(
this
,
indexName
,
cols
,
indexType
);
for
(
SearchRow
row
:
scan
.
set
)
{
index
.
add
(
session
,
(
Row
)
row
);
}
indexes
.
add
(
index
);
dataMoficationId
++;
setModified
();
return
index
;
}
@Override
public
boolean
lock
(
Session
session
,
boolean
exclusive
,
boolean
forceLockEvenInMvcc
)
{
return
true
;
}
@Override
public
boolean
isLockedExclusively
()
{
return
false
;
}
@Override
public
boolean
isDeterministic
()
{
return
false
;
}
@Override
public
Index
getUniqueIndex
()
{
return
null
;
}
@Override
public
String
getTableType
()
{
return
EXTERNAL_TABLE_ENGINE
;
}
@Override
public
Index
getScanIndex
(
Session
session
)
{
return
scan
;
}
@Override
public
long
getRowCountApproximation
()
{
return
getScanIndex
(
null
).
getRowCountApproximation
();
}
@Override
public
long
getRowCount
(
Session
session
)
{
return
scan
.
getRowCount
(
session
);
}
@Override
public
long
getMaxDataModificationId
()
{
return
dataMoficationId
;
}
@Override
public
ArrayList
<
Index
>
getIndexes
()
{
return
indexes
;
}
@Override
public
long
getDiskSpaceUsed
()
{
return
0
;
}
@Override
public
void
close
(
Session
session
)
{
// No-op.
}
@Override
public
void
checkSupportAlter
()
{
// No-op.
}
@Override
public
boolean
canGetRowCount
()
{
return
true
;
}
@Override
public
boolean
canDrop
()
{
return
true
;
}
}
/**
*/
private
static
class
TreeSetIndex
extends
BaseIndex
implements
Comparator
<
SearchRow
>
{
private
final
TreeSet
<
SearchRow
>
set
=
new
TreeSet
<
SearchRow
>(
this
);
TreeSetIndex
(
Table
t
,
String
name
,
IndexColumn
[]
cols
,
IndexType
type
)
{
initBaseIndex
(
t
,
0
,
name
,
cols
,
type
);
}
@Override
public
int
compare
(
SearchRow
o1
,
SearchRow
o2
)
{
int
res
=
compareRows
(
o1
,
o2
);
if
(
res
==
0
&&
(
o1
.
getKey
()
==
Long
.
MAX_VALUE
||
o2
.
getKey
()
==
Long
.
MAX_VALUE
))
{
res
=
-
1
;
}
return
res
;
}
@Override
public
void
close
(
Session
session
)
{
// No-op.
}
@Override
public
void
add
(
Session
session
,
Row
row
)
{
set
.
add
(
row
);
}
@Override
public
void
remove
(
Session
session
,
Row
row
)
{
set
.
remove
(
row
);
}
private
SearchRow
mark
(
SearchRow
row
)
{
if
(
row
!=
null
)
{
// Mark this row to be a search row.
row
.
setKey
(
Long
.
MAX_VALUE
);
}
return
row
;
}
@Override
public
Cursor
find
(
Session
session
,
SearchRow
first
,
SearchRow
last
)
{
Set
<
SearchRow
>
subSet
;
if
(
first
!=
null
&&
last
!=
null
&&
compareRows
(
last
,
first
)
<
0
)
{
subSet
=
Collections
.
emptySet
();
}
else
{
if
(
first
!=
null
)
{
first
=
set
.
floor
(
mark
(
first
));
}
if
(
last
!=
null
)
{
last
=
set
.
ceiling
(
mark
(
last
));
}
if
(
first
==
null
&&
last
==
null
)
{
subSet
=
set
;
}
else
if
(
first
!=
null
)
{
subSet
=
set
.
tailSet
(
first
,
true
);
}
else
if
(
last
!=
null
)
{
subSet
=
set
.
headSet
(
last
,
true
);
}
else
{
subSet
=
set
.
subSet
(
first
,
true
,
last
,
true
);
}
}
return
new
IteratorCursor
(
subSet
.
iterator
());
}
@Override
public
double
getCost
(
Session
session
,
int
[]
masks
,
TableFilter
filter
,
SortOrder
sortOrder
)
{
return
getCostRangeIndex
(
masks
,
set
.
size
(),
filter
,
sortOrder
);
}
@Override
public
void
remove
(
Session
session
)
{
// No-op.
}
@Override
public
void
truncate
(
Session
session
)
{
set
.
clear
();
}
@Override
public
boolean
canGetFirstOrLast
()
{
return
true
;
}
@Override
public
Cursor
findFirstOrLast
(
Session
session
,
boolean
first
)
{
return
new
SingleRowCursor
((
Row
)
(
set
.
isEmpty
()
?
null
:
first
?
set
.
first
()
:
set
.
last
()));
}
@Override
public
boolean
needRebuild
()
{
return
true
;
}
@Override
public
long
getRowCount
(
Session
session
)
{
return
set
.
size
();
}
@Override
public
long
getRowCountApproximation
()
{
return
getRowCount
(
null
);
}
@Override
public
long
getDiskSpaceUsed
()
{
return
0
;
}
@Override
public
void
checkRename
()
{
// No-op.
}
}
/**
*/
private
static
class
IteratorCursor
implements
Cursor
{
private
Iterator
<
SearchRow
>
iter
;
private
Row
current
;
public
IteratorCursor
(
Iterator
<
SearchRow
>
iter
)
{
this
.
iter
=
iter
;
}
@Override
public
boolean
previous
()
{
throw
DbException
.
getUnsupportedException
(
"prev"
);
}
@Override
public
boolean
next
()
{
if
(
iter
.
hasNext
())
{
current
=
(
Row
)
iter
.
next
();
return
true
;
}
current
=
null
;
return
false
;
}
@Override
public
SearchRow
getSearchRow
()
{
return
get
();
}
@Override
public
Row
get
()
{
return
current
;
}
}
/**
*/
private
static
class
RowComparator
implements
Comparator
<
List
<
Object
>>
{
private
int
[]
cols
;
}
public
RowComparator
(
int
...
cols
)
{
this
.
cols
=
cols
;
}
@SuppressWarnings
(
"unchecked"
)
@Override
public
int
compare
(
List
<
Object
>
row1
,
List
<
Object
>
row2
)
{
if
(
row1
.
size
()
!=
row2
.
size
())
{
throw
new
IllegalStateException
(
"Row size mismatch."
);
}
for
(
int
i
=
0
;
i
<
cols
.
length
;
i
++)
{
int
col
=
cols
[
i
];
Comparable
<
Object
>
o1
=
(
Comparable
<
Object
>)
row1
.
get
(
col
);
Comparable
<
Object
>
o2
=
(
Comparable
<
Object
>)
row2
.
get
(
col
);
if
(
o1
==
null
)
{
return
o2
==
null
?
0
:
-
1
;
}
if
(
o2
==
null
)
{
return
1
;
}
int
res
=
o1
.
compareTo
(
o2
);
if
(
res
!=
0
)
{
return
res
;
}
}
return
0
;
}
}
/**
*/
private
abstract
static
class
RowFilter
{
protected
abstract
boolean
accept
(
List
<
Object
>
row
);
protected
Integer
getInt
(
List
<
Object
>
row
,
int
col
)
{
return
(
Integer
)
row
.
get
(
col
);
}
protected
Long
getLong
(
List
<
Object
>
row
,
int
col
)
{
return
(
Long
)
row
.
get
(
col
);
}
protected
String
getString
(
List
<
Object
>
row
,
int
col
)
{
return
(
String
)
row
.
get
(
col
);
}
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论