Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
18a3b3c2
提交
18a3b3c2
authored
8月 13, 2009
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
An optimization for IN(..) and IN(SELECT...) using the system property h2.optimizeInList
上级
284e2b74
显示空白字符变更
内嵌
并排
正在显示
12 个修改的文件
包含
451 行增加
和
129 行删除
+451
-129
Parser.java
h2/src/main/org/h2/command/Parser.java
+1
-1
SysProperties.java
h2/src/main/org/h2/constant/SysProperties.java
+8
-0
CompareLike.java
h2/src/main/org/h2/expression/CompareLike.java
+3
-3
Comparison.java
h2/src/main/org/h2/expression/Comparison.java
+14
-2
ConditionIn.java
h2/src/main/org/h2/expression/ConditionIn.java
+43
-31
ConditionInSelect.java
h2/src/main/org/h2/expression/ConditionInSelect.java
+25
-2
ExpressionColumn.java
h2/src/main/org/h2/expression/ExpressionColumn.java
+1
-1
ValueExpression.java
h2/src/main/org/h2/expression/ValueExpression.java
+1
-1
IndexCondition.java
h2/src/main/org/h2/index/IndexCondition.java
+125
-9
IndexCursor.java
h2/src/main/org/h2/index/IndexCursor.java
+207
-0
MetaTable.java
h2/src/main/org/h2/table/MetaTable.java
+1
-0
TableFilter.java
h2/src/main/org/h2/table/TableFilter.java
+22
-79
没有找到文件。
h2/src/main/org/h2/command/Parser.java
浏览文件 @
18a3b3c2
...
...
@@ -1715,7 +1715,7 @@ public class Parser {
read
(
"NULL"
);
r
=
new
Comparison
(
session
,
type
,
r
,
null
);
}
else
if
(
readIf
(
"IN"
))
{
if
(
SysProperties
.
OPTIMIZE_IN
)
{
if
(
SysProperties
.
OPTIMIZE_IN
&&
!
SysProperties
.
OPTIMIZE_IN_LIST
)
{
recompileAlways
=
true
;
}
read
(
"("
);
...
...
h2/src/main/org/h2/constant/SysProperties.java
浏览文件 @
18a3b3c2
...
...
@@ -437,6 +437,14 @@ public class SysProperties {
*/
public
static
final
boolean
OPTIMIZE_IN
=
getBooleanSetting
(
"h2.optimizeIn"
,
true
);
/**
* System property <code>h2.optimizeInList</code> (default: false).<br />
* Optimize IN(...) and IN(SELECT ...) comparisons. This includes
* optimization for SELECT, DELETE, and UPDATE. Overrides h2.optimizeIn and
* h2.optimizeInJoin if enabled.
*/
public
static
final
boolean
OPTIMIZE_IN_LIST
=
getBooleanSetting
(
"h2.optimizeInList"
,
false
);
/**
* System property <code>h2.optimizeInJoin</code> (default: false).<br />
* Optimize IN(...) comparisons by converting them to inner joins.
...
...
h2/src/main/org/h2/expression/CompareLike.java
浏览文件 @
18a3b3c2
...
...
@@ -174,14 +174,14 @@ public class CompareLike extends Condition {
}
String
begin
=
buff
.
toString
();
if
(
maxMatch
==
patternLength
)
{
filter
.
addIndexCondition
(
new
IndexCondition
(
Comparison
.
EQUAL
,
l
,
ValueExpression
filter
.
addIndexCondition
(
IndexCondition
.
get
(
Comparison
.
EQUAL
,
l
,
ValueExpression
.
get
(
ValueString
.
get
(
begin
))));
}
else
{
// TODO check if this is correct according to Unicode rules (code
// points)
String
end
;
if
(
begin
.
length
()
>
0
)
{
filter
.
addIndexCondition
(
new
IndexCondition
(
Comparison
.
BIGGER_EQUAL
,
l
,
ValueExpression
.
get
(
ValueString
filter
.
addIndexCondition
(
IndexCondition
.
get
(
Comparison
.
BIGGER_EQUAL
,
l
,
ValueExpression
.
get
(
ValueString
.
get
(
begin
))));
char
next
=
begin
.
charAt
(
begin
.
length
()
-
1
);
// search the 'next' unicode character (or at least a character
...
...
@@ -189,7 +189,7 @@ public class CompareLike extends Condition {
for
(
int
i
=
1
;
i
<
2000
;
i
++)
{
end
=
begin
.
substring
(
0
,
begin
.
length
()
-
1
)
+
(
char
)
(
next
+
i
);
if
(
compareMode
.
compareString
(
begin
,
end
,
ignoreCase
)
==
-
1
)
{
filter
.
addIndexCondition
(
new
IndexCondition
(
Comparison
.
SMALLER
,
l
,
ValueExpression
filter
.
addIndexCondition
(
IndexCondition
.
get
(
Comparison
.
SMALLER
,
l
,
ValueExpression
.
get
(
ValueString
.
get
(
end
))));
break
;
}
...
...
h2/src/main/org/h2/expression/Comparison.java
浏览文件 @
18a3b3c2
...
...
@@ -71,6 +71,18 @@ public class Comparison extends Condition {
*/
public
static
final
int
FALSE
=
8
;
/**
* This is a pseudo comparison type that is only used for index conditions.
* It means equals any value of a list. Example: IN(1, 2, 3).
*/
public
static
final
int
IN_LIST
=
9
;
/**
* This is a pseudo comparison type that is only used for index conditions.
* It means equals any value of a list. Example: IN(SELECT ...).
*/
public
static
final
int
IN_QUERY
=
10
;
private
final
Database
database
;
private
final
int
compareType
;
private
Expression
left
;
...
...
@@ -366,10 +378,10 @@ public class Comparison extends Condition {
}
if
(
addIndex
)
{
if
(
l
!=
null
)
{
filter
.
addIndexCondition
(
new
IndexCondition
(
compareType
,
l
,
right
));
filter
.
addIndexCondition
(
IndexCondition
.
get
(
compareType
,
l
,
right
));
}
else
if
(
r
!=
null
)
{
int
compareRev
=
getReversedCompareType
(
compareType
);
filter
.
addIndexCondition
(
new
IndexCondition
(
compareRev
,
r
,
left
));
filter
.
addIndexCondition
(
IndexCondition
.
get
(
compareRev
,
r
,
left
));
}
}
return
;
...
...
h2/src/main/org/h2/expression/ConditionIn.java
浏览文件 @
18a3b3c2
...
...
@@ -7,7 +7,6 @@
package
org
.
h2
.
expression
;
import
java.sql.SQLException
;
import
org.h2.command.dml.Select
;
import
org.h2.constant.SysProperties
;
import
org.h2.engine.Constants
;
...
...
@@ -34,19 +33,19 @@ public class ConditionIn extends Condition {
private
final
Database
database
;
private
Expression
left
;
private
final
ObjectArray
<
Expression
>
value
s
;
private
final
ObjectArray
<
Expression
>
value
List
;
private
Value
min
,
max
;
private
int
queryLevel
;
public
ConditionIn
(
Database
database
,
Expression
left
,
ObjectArray
<
Expression
>
values
)
{
this
.
database
=
database
;
this
.
left
=
left
;
this
.
value
s
=
values
;
this
.
value
List
=
values
;
}
public
Value
getValue
(
Session
session
)
throws
SQLException
{
Value
l
=
left
.
getValue
(
session
);
if
(
value
s
.
size
()
==
0
)
{
if
(
value
List
.
size
()
==
0
)
{
return
ValueBoolean
.
get
(
false
);
}
if
(
l
==
ValueNull
.
INSTANCE
)
{
...
...
@@ -54,11 +53,12 @@ public class ConditionIn extends Condition {
}
boolean
result
=
false
;
boolean
hasNull
=
false
;
for
(
Expression
e
:
value
s
)
{
for
(
Expression
e
:
value
List
)
{
Value
r
=
e
.
getValue
(
session
);
if
(
r
==
ValueNull
.
INSTANCE
)
{
hasNull
=
true
;
}
else
{
r
=
r
.
convertTo
(
l
.
getType
());
result
=
Comparison
.
compareNotNull
(
database
,
l
,
r
,
Comparison
.
EQUAL
);
if
(
result
)
{
break
;
...
...
@@ -73,14 +73,14 @@ public class ConditionIn extends Condition {
public
void
mapColumns
(
ColumnResolver
resolver
,
int
queryLevel
)
throws
SQLException
{
left
.
mapColumns
(
resolver
,
queryLevel
);
for
(
Expression
e
:
value
s
)
{
for
(
Expression
e
:
value
List
)
{
e
.
mapColumns
(
resolver
,
queryLevel
);
}
this
.
queryLevel
=
Math
.
max
(
queryLevel
,
this
.
queryLevel
);
}
public
Expression
optimize
(
Session
session
)
throws
SQLException
{
if
(
value
s
.
size
()
==
0
)
{
if
(
value
List
.
size
()
==
0
)
{
return
ValueExpression
.
get
(
ValueBoolean
.
get
(
false
));
}
left
=
left
.
optimize
(
session
);
...
...
@@ -89,25 +89,24 @@ public class ConditionIn extends Condition {
return
left
;
}
boolean
allValuesConstant
=
true
;
for
(
int
i
=
0
;
i
<
value
s
.
size
();
i
++)
{
Expression
e
=
value
s
.
get
(
i
);
for
(
int
i
=
0
;
i
<
value
List
.
size
();
i
++)
{
Expression
e
=
value
List
.
get
(
i
);
e
=
e
.
optimize
(
session
);
if
(
allValuesConstant
&&
!
e
.
isConstant
())
{
allValuesConstant
=
false
;
}
value
s
.
set
(
i
,
e
);
value
List
.
set
(
i
,
e
);
}
if
(
constant
&&
allValuesConstant
)
{
return
ValueExpression
.
get
(
getValue
(
session
));
}
// TODO optimization: could use index in some cases (sort, use min and max)
if
(
values
.
size
()
==
1
)
{
Expression
right
=
values
.
get
(
0
);
if
(
valueList
.
size
()
==
1
)
{
Expression
right
=
valueList
.
get
(
0
);
Expression
expr
=
new
Comparison
(
session
,
Comparison
.
EQUAL
,
left
,
right
);
expr
=
expr
.
optimize
(
session
);
return
expr
;
}
if
(
SysProperties
.
OPTIMIZE_IN
)
{
if
(
SysProperties
.
OPTIMIZE_IN
&&
!
SysProperties
.
OPTIMIZE_IN_LIST
)
{
int
dataType
=
left
.
getType
();
ExpressionVisitor
independent
=
ExpressionVisitor
.
get
(
ExpressionVisitor
.
INDEPENDENT
);
independent
.
setQueryLevel
(
queryLevel
);
...
...
@@ -116,11 +115,11 @@ public class ConditionIn extends Condition {
Column
column
=
((
ExpressionColumn
)
left
).
getColumn
();
boolean
nullable
=
column
.
isNullable
();
CompareMode
mode
=
session
.
getDatabase
().
getCompareMode
();
for
(
int
i
=
0
;
i
<
value
s
.
size
();
i
++)
{
Expression
e
=
value
s
.
get
(
i
);
for
(
int
i
=
0
;
i
<
value
List
.
size
();
i
++)
{
Expression
e
=
value
List
.
get
(
i
);
Value
v
=
e
.
getValue
(
session
);
v
=
v
.
convertTo
(
dataType
);
value
s
.
set
(
i
,
ValueExpression
.
get
(
v
));
value
List
.
set
(
i
,
ValueExpression
.
get
(
v
));
if
(
min
==
null
||
min
.
compareTo
(
v
,
mode
)
>
0
)
{
if
(
v
!=
ValueNull
.
INSTANCE
||
nullable
)
{
min
=
v
;
...
...
@@ -137,26 +136,36 @@ public class ConditionIn extends Condition {
}
public
void
createIndexConditions
(
Session
session
,
TableFilter
filter
)
{
if
(!
SysProperties
.
OPTIMIZE_IN
)
{
if
(!
(
left
instanceof
ExpressionColumn
)
)
{
return
;
}
if
(
min
==
null
&&
max
==
null
)
{
ExpressionColumn
l
=
(
ExpressionColumn
)
left
;
if
(
filter
!=
l
.
getTableFilter
())
{
return
;
}
if
(!(
left
instanceof
ExpressionColumn
))
{
if
(
SysProperties
.
OPTIMIZE_IN_LIST
)
{
ExpressionVisitor
visitor
=
ExpressionVisitor
.
get
(
ExpressionVisitor
.
NOT_FROM_RESOLVER
);
visitor
.
setResolver
(
filter
);
for
(
Expression
e
:
valueList
)
{
if
(!
e
.
isEverything
(
visitor
))
{
return
;
}
ExpressionColumn
l
=
(
ExpressionColumn
)
left
;
if
(
filter
!=
l
.
getTableFilter
())
{
}
filter
.
addIndexCondition
(
IndexCondition
.
getInList
(
l
,
valueList
));
}
if
(!
SysProperties
.
OPTIMIZE_IN
)
{
return
;
}
filter
.
addIndexCondition
(
new
IndexCondition
(
Comparison
.
BIGGER_EQUAL
,
l
,
ValueExpression
.
get
(
min
)));
filter
.
addIndexCondition
(
new
IndexCondition
(
Comparison
.
SMALLER_EQUAL
,
l
,
ValueExpression
.
get
(
max
)));
if
(
min
==
null
&&
max
==
null
)
{
return
;
}
filter
.
addIndexCondition
(
IndexCondition
.
get
(
Comparison
.
BIGGER_EQUAL
,
l
,
ValueExpression
.
get
(
min
)));
filter
.
addIndexCondition
(
IndexCondition
.
get
(
Comparison
.
SMALLER_EQUAL
,
l
,
ValueExpression
.
get
(
max
)));
}
public
void
setEvaluatable
(
TableFilter
tableFilter
,
boolean
b
)
{
left
.
setEvaluatable
(
tableFilter
,
b
);
for
(
Expression
e
:
value
s
)
{
for
(
Expression
e
:
value
List
)
{
e
.
setEvaluatable
(
tableFilter
,
b
);
}
}
...
...
@@ -164,7 +173,7 @@ public class ConditionIn extends Condition {
public
String
getSQL
()
{
StatementBuilder
buff
=
new
StatementBuilder
(
"("
);
buff
.
append
(
left
.
getSQL
()).
append
(
" IN("
);
for
(
Expression
e
:
value
s
)
{
for
(
Expression
e
:
value
List
)
{
buff
.
appendExceptFirst
(
", "
);
buff
.
append
(
e
.
getSQL
());
}
...
...
@@ -173,7 +182,7 @@ public class ConditionIn extends Condition {
public
void
updateAggregate
(
Session
session
)
throws
SQLException
{
left
.
updateAggregate
(
session
);
for
(
Expression
e
:
value
s
)
{
for
(
Expression
e
:
value
List
)
{
e
.
updateAggregate
(
session
);
}
}
...
...
@@ -186,7 +195,7 @@ public class ConditionIn extends Condition {
}
private
boolean
areAllValues
(
ExpressionVisitor
visitor
)
{
for
(
Expression
e
:
value
s
)
{
for
(
Expression
e
:
value
List
)
{
if
(!
e
.
isEverything
(
visitor
))
{
return
false
;
}
...
...
@@ -196,13 +205,16 @@ public class ConditionIn extends Condition {
public
int
getCost
()
{
int
cost
=
left
.
getCost
();
for
(
Expression
e
:
value
s
)
{
for
(
Expression
e
:
value
List
)
{
cost
+=
e
.
getCost
();
}
return
cost
;
}
public
Expression
optimizeInJoin
(
Session
session
,
Select
select
)
throws
SQLException
{
if
(
SysProperties
.
OPTIMIZE_IN_LIST
)
{
return
this
;
}
if
(!
areAllValues
(
ExpressionVisitor
.
get
(
ExpressionVisitor
.
EVALUATABLE
)))
{
return
this
;
}
...
...
@@ -219,11 +231,11 @@ public class ConditionIn extends Condition {
}
Database
db
=
session
.
getDatabase
();
Schema
mainSchema
=
db
.
getSchema
(
Constants
.
SCHEMA_MAIN
);
int
rowCount
=
value
s
.
size
();
int
rowCount
=
value
List
.
size
();
TableFunction
function
=
new
TableFunction
(
database
,
Function
.
getFunctionInfo
(
"TABLE_DISTINCT"
),
rowCount
);
Expression
[]
array
=
new
Expression
[
rowCount
];
for
(
int
i
=
0
;
i
<
rowCount
;
i
++)
{
Expression
e
=
value
s
.
get
(
i
);
Expression
e
=
value
List
.
get
(
i
);
array
[
i
]
=
e
;
}
ExpressionList
list
=
new
ExpressionList
(
array
);
...
...
h2/src/main/org/h2/expression/ConditionInSelect.java
浏览文件 @
18a3b3c2
...
...
@@ -11,9 +11,11 @@ import java.sql.SQLException;
import
org.h2.command.dml.Query
;
import
org.h2.command.dml.Select
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.SysProperties
;
import
org.h2.engine.Database
;
import
org.h2.engine.Session
;
import
org.h2.index.Index
;
import
org.h2.index.IndexCondition
;
import
org.h2.message.Message
;
import
org.h2.result.LocalResult
;
import
org.h2.table.ColumnResolver
;
...
...
@@ -94,8 +96,7 @@ public class ConditionInSelect extends Condition {
if
(
query
.
getColumnCount
()
!=
1
)
{
throw
Message
.
getSQLException
(
ErrorCode
.
SUBQUERY_IS_NOT_SINGLE_COLUMN
);
}
// Can not optimize IN(SELECT...): the data may change
// However, could transform to an inner join
// Can not optimize: the data may change
return
this
;
}
...
...
@@ -125,6 +126,9 @@ public class ConditionInSelect extends Condition {
public
Expression
optimizeInJoin
(
Session
session
,
Select
select
)
throws
SQLException
{
query
.
setDistinct
(
true
);
if
(
SysProperties
.
OPTIMIZE_IN_LIST
)
{
return
this
;
}
if
(
all
||
compareType
!=
Comparison
.
EQUAL
)
{
return
this
;
}
...
...
@@ -157,4 +161,23 @@ public class ConditionInSelect extends Condition {
return
on
;
}
public
void
createIndexConditions
(
Session
session
,
TableFilter
filter
)
{
if
(!
SysProperties
.
OPTIMIZE_IN_LIST
)
{
return
;
}
if
(!(
left
instanceof
ExpressionColumn
))
{
return
;
}
ExpressionColumn
l
=
(
ExpressionColumn
)
left
;
if
(
filter
!=
l
.
getTableFilter
())
{
return
;
}
ExpressionVisitor
visitor
=
ExpressionVisitor
.
get
(
ExpressionVisitor
.
NOT_FROM_RESOLVER
);
visitor
.
setResolver
(
filter
);
if
(!
query
.
isEverything
(
visitor
))
{
return
;
}
filter
.
addIndexCondition
(
IndexCondition
.
getInQuery
(
l
,
query
));
}
}
h2/src/main/org/h2/expression/ExpressionColumn.java
浏览文件 @
18a3b3c2
...
...
@@ -266,7 +266,7 @@ public class ExpressionColumn extends Expression {
public
void
createIndexConditions
(
Session
session
,
TableFilter
filter
)
{
TableFilter
tf
=
getTableFilter
();
if
(
filter
==
tf
&&
column
.
getType
()
==
Value
.
BOOLEAN
)
{
IndexCondition
cond
=
new
IndexCondition
(
Comparison
.
EQUAL
,
this
,
ValueExpression
IndexCondition
cond
=
IndexCondition
.
get
(
Comparison
.
EQUAL
,
this
,
ValueExpression
.
get
(
ValueBoolean
.
get
(
true
)));
filter
.
addIndexCondition
(
cond
);
}
...
...
h2/src/main/org/h2/expression/ValueExpression.java
浏览文件 @
18a3b3c2
...
...
@@ -80,7 +80,7 @@ public class ValueExpression extends Expression {
if
(
value
.
getType
()
==
Value
.
BOOLEAN
)
{
boolean
v
=
((
ValueBoolean
)
value
).
getBoolean
().
booleanValue
();
if
(!
v
)
{
filter
.
addIndexCondition
(
new
IndexCondition
(
Comparison
.
FALSE
,
null
,
this
));
filter
.
addIndexCondition
(
IndexCondition
.
get
(
Comparison
.
FALSE
,
null
,
this
));
}
}
}
...
...
h2/src/main/org/h2/index/IndexCondition.java
浏览文件 @
18a3b3c2
...
...
@@ -7,14 +7,21 @@
package
org
.
h2
.
index
;
import
java.sql.SQLException
;
import
java.util.Arrays
;
import
java.util.Comparator
;
import
java.util.HashSet
;
import
org.h2.command.dml.Query
;
import
org.h2.engine.Session
;
import
org.h2.expression.Comparison
;
import
org.h2.expression.Expression
;
import
org.h2.expression.ExpressionColumn
;
import
org.h2.expression.ExpressionVisitor
;
import
org.h2.message.Message
;
import
org.h2.result.LocalResult
;
import
org.h2.table.Column
;
import
org.h2.util.ObjectArray
;
import
org.h2.util.StatementBuilder
;
import
org.h2.value.CompareMode
;
import
org.h2.value.Value
;
/**
...
...
@@ -50,20 +57,56 @@ public class IndexCondition {
public
static
final
int
ALWAYS_FALSE
=
8
;
private
Column
column
;
private
Expression
expression
;
private
int
compareType
;
private
Expression
expression
;
private
ObjectArray
<
Expression
>
expressionList
;
private
Query
expressionQuery
;
private
IndexCondition
(
int
compareType
,
ExpressionColumn
column
,
Expression
expression
)
{
this
.
compareType
=
compareType
;
this
.
column
=
column
==
null
?
null
:
column
.
getColumn
();
this
.
expression
=
expression
;
}
/**
* Create an index condition with the given parameters.
*
* @param compareType the comparison type
* @param column the column
* @param expression the expression
* @return the index condition
*/
public
IndexCondition
(
int
compareType
,
ExpressionColumn
column
,
Expression
expression
)
{
this
.
compareType
=
compareType
;
this
.
column
=
column
==
null
?
null
:
column
.
getColumn
();
this
.
expression
=
expression
;
public
static
IndexCondition
get
(
int
compareType
,
ExpressionColumn
column
,
Expression
expression
)
{
return
new
IndexCondition
(
compareType
,
column
,
expression
);
}
/**
* Create an index condition with the compare type IN_LIST and with the
* given parameters.
*
* @param column the column
* @param list the expression list
* @return the index condition
*/
public
static
IndexCondition
getInList
(
ExpressionColumn
column
,
ObjectArray
<
Expression
>
list
)
{
IndexCondition
cond
=
new
IndexCondition
(
Comparison
.
IN_LIST
,
column
,
null
);
cond
.
expressionList
=
list
;
return
cond
;
}
/**
* Create an index condition with the compare type IN_QUERY and with the
* given parameters.
*
* @param column the column
* @param query the select statement
* @return the index condition
*/
public
static
IndexCondition
getInQuery
(
ExpressionColumn
column
,
Query
query
)
{
IndexCondition
cond
=
new
IndexCondition
(
Comparison
.
IN_QUERY
,
column
,
null
);
cond
.
expressionQuery
=
query
;
return
cond
;
}
/**
...
...
@@ -76,6 +119,47 @@ public class IndexCondition {
return
expression
.
getValue
(
session
);
}
/**
* Get the current value list of the expression. The value list is of the
* same type as the column, distinct, and sorted.
*
* @param session the session
* @return the value list
*/
public
Value
[]
getCurrentValueList
(
Session
session
)
throws
SQLException
{
HashSet
<
Value
>
valueSet
=
new
HashSet
<
Value
>();
int
dataType
=
column
.
getType
();
for
(
Expression
e
:
expressionList
)
{
Value
v
=
e
.
getValue
(
session
);
v
=
v
.
convertTo
(
dataType
);
valueSet
.
add
(
v
);
}
Value
[]
array
=
new
Value
[
valueSet
.
size
()];
valueSet
.
toArray
(
array
);
final
CompareMode
mode
=
session
.
getDatabase
().
getCompareMode
();
Arrays
.
sort
(
array
,
new
Comparator
<
Value
>()
{
public
int
compare
(
Value
o1
,
Value
o2
)
{
try
{
return
o1
.
compareTo
(
o2
,
mode
);
}
catch
(
SQLException
e
)
{
throw
Message
.
convertToInternal
(
e
);
}
}
});
return
array
;
}
/**
* Get the current result of the expression. The rows may not be of the same
* type, therefore the rows may not be unique.
*
* @param session the session
* @return the result
*/
public
LocalResult
getCurrentResult
(
Session
session
)
throws
SQLException
{
return
expressionQuery
.
query
(
0
);
}
/**
* Get the SQL snippet of this comparison.
*
...
...
@@ -85,7 +169,7 @@ public class IndexCondition {
if
(
compareType
==
Comparison
.
FALSE
)
{
return
"FALSE"
;
}
St
ringBuilder
buff
=
new
String
Builder
();
St
atementBuilder
buff
=
new
Statement
Builder
();
buff
.
append
(
column
.
getSQL
());
switch
(
compareType
)
{
case
Comparison
.
EQUAL
:
...
...
@@ -103,10 +187,25 @@ public class IndexCondition {
case
Comparison
.
SMALLER
:
buff
.
append
(
" < "
);
break
;
case
Comparison
.
IN_LIST
:
buff
.
append
(
" IN("
);
for
(
Expression
e
:
expressionList
)
{
buff
.
appendExceptFirst
(
", "
);
buff
.
append
(
e
.
getSQL
());
}
buff
.
append
(
')'
);
break
;
case
Comparison
.
IN_QUERY
:
buff
.
append
(
" IN("
);
buff
.
append
(
expressionQuery
.
getPlanSQL
());
buff
.
append
(
')'
);
break
;
default
:
Message
.
throwInternalError
(
"type="
+
compareType
);
}
if
(
expression
!=
null
)
{
buff
.
append
(
expression
.
getSQL
());
}
return
buff
.
toString
();
}
...
...
@@ -120,6 +219,8 @@ public class IndexCondition {
case
Comparison
.
FALSE
:
return
ALWAYS_FALSE
;
case
Comparison
.
EQUAL
:
case
Comparison
.
IN_LIST
:
case
Comparison
.
IN_QUERY
:
return
EQUALITY
;
case
Comparison
.
BIGGER_EQUAL
:
case
Comparison
.
BIGGER
:
...
...
@@ -175,6 +276,10 @@ public class IndexCondition {
}
}
public
int
getCompareType
()
{
return
compareType
;
}
/**
* Get the referenced column.
*
...
...
@@ -190,7 +295,18 @@ public class IndexCondition {
* @return true if it can be evaluated
*/
public
boolean
isEvaluatable
()
{
if
(
expression
!=
null
)
{
return
expression
.
isEverything
(
ExpressionVisitor
.
EVALUATABLE
);
}
if
(
expressionList
!=
null
)
{
for
(
Expression
e
:
expressionList
)
{
if
(!
e
.
isEverything
(
ExpressionVisitor
.
EVALUATABLE
))
{
return
false
;
}
}
return
true
;
}
return
expressionQuery
.
isEverything
(
ExpressionVisitor
.
EVALUATABLE
);
}
}
h2/src/main/org/h2/index/IndexCursor.java
0 → 100644
浏览文件 @
18a3b3c2
/*
* Copyright 2004-2009 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
index
;
import
java.sql.SQLException
;
import
java.util.HashSet
;
import
org.h2.engine.Session
;
import
org.h2.expression.Comparison
;
import
org.h2.message.Message
;
import
org.h2.result.LocalResult
;
import
org.h2.result.Row
;
import
org.h2.result.SearchRow
;
import
org.h2.result.SortOrder
;
import
org.h2.table.Column
;
import
org.h2.table.IndexColumn
;
import
org.h2.table.Table
;
import
org.h2.util.ObjectArray
;
import
org.h2.value.Value
;
/**
* The filter used to walk through an index. This class filters supports IN(..)
* and IN(SELECT ...) optimizations.
*/
public
class
IndexCursor
implements
Cursor
{
private
Session
session
;
private
Index
index
;
private
Table
table
;
private
IndexColumn
[]
indexColumns
;
private
boolean
alwaysFalse
;
private
SearchRow
start
,
end
;
private
Cursor
cursor
;
private
Column
inColumn
;
private
int
inListIndex
;
private
Value
[]
inList
;
private
LocalResult
inResult
;
private
HashSet
<
Value
>
inResultTested
;
public
IndexCursor
(
Session
session
)
{
this
.
session
=
session
;
}
public
void
setIndex
(
Index
index
)
{
this
.
index
=
index
;
this
.
table
=
index
.
getTable
();
Column
[]
columns
=
table
.
getColumns
();
indexColumns
=
new
IndexColumn
[
columns
.
length
];
IndexColumn
[]
idxCols
=
index
.
getIndexColumns
();
if
(
idxCols
!=
null
)
{
for
(
int
i
=
0
;
i
<
columns
.
length
;
i
++)
{
int
idx
=
index
.
getColumnIndex
(
columns
[
i
]);
if
(
idx
>=
0
)
{
indexColumns
[
i
]
=
idxCols
[
idx
];
}
}
}
}
/**
* Re-evaluate the start and end values of the index search for rows.
*
* @param indexConditions the index conditions
*/
public
void
find
(
ObjectArray
<
IndexCondition
>
indexConditions
)
throws
SQLException
{
alwaysFalse
=
false
;
start
=
end
=
null
;
inList
=
null
;
inResult
=
null
;
inResultTested
=
new
HashSet
<
Value
>();
for
(
IndexCondition
condition
:
indexConditions
)
{
if
(
condition
.
isAlwaysFalse
())
{
alwaysFalse
=
true
;
break
;
}
Column
column
=
condition
.
getColumn
();
int
type
=
column
.
getType
();
int
id
=
column
.
getColumnId
();
if
(
condition
.
getCompareType
()
==
Comparison
.
IN_LIST
)
{
this
.
inColumn
=
column
;
inList
=
condition
.
getCurrentValueList
(
session
);
inListIndex
=
0
;
return
;
}
else
if
(
condition
.
getCompareType
()
==
Comparison
.
IN_QUERY
)
{
this
.
inColumn
=
column
;
inResult
=
condition
.
getCurrentResult
(
session
);
return
;
}
else
{
Value
v
=
condition
.
getCurrentValue
(
session
).
convertTo
(
type
);
boolean
isStart
=
condition
.
isStart
();
boolean
isEnd
=
condition
.
isEnd
();
IndexColumn
idxCol
=
indexColumns
[
id
];
if
(
idxCol
!=
null
&&
(
idxCol
.
sortType
&
SortOrder
.
DESCENDING
)
!=
0
)
{
// if the index column is sorted the other way, we swap end and start
// NULLS_FIRST / NULLS_LAST is not a problem, as nulls never match anyway
boolean
temp
=
isStart
;
isStart
=
isEnd
;
isEnd
=
temp
;
}
if
(
isStart
)
{
start
=
getSearchRow
(
start
,
id
,
v
,
true
);
}
if
(
isEnd
)
{
end
=
getSearchRow
(
end
,
id
,
v
,
false
);
}
}
}
if
(!
alwaysFalse
)
{
cursor
=
index
.
find
(
session
,
start
,
end
);
}
}
private
SearchRow
getSearchRow
(
SearchRow
row
,
int
id
,
Value
v
,
boolean
max
)
throws
SQLException
{
if
(
row
==
null
)
{
row
=
table
.
getTemplateRow
();
}
else
{
v
=
getMax
(
row
.
getValue
(
id
),
v
,
max
);
}
row
.
setValue
(
id
,
v
);
return
row
;
}
private
Value
getMax
(
Value
a
,
Value
b
,
boolean
bigger
)
throws
SQLException
{
if
(
a
==
null
)
{
return
b
;
}
else
if
(
b
==
null
)
{
return
a
;
}
int
comp
=
a
.
compareTo
(
b
,
table
.
getDatabase
().
getCompareMode
());
if
(!
bigger
)
{
comp
=
-
comp
;
}
return
comp
>
0
?
a
:
b
;
}
/**
* Check if the result is empty for sure.
*
* @return true if it is
*/
public
boolean
isAlwaysFalse
()
{
return
alwaysFalse
;
}
public
Row
get
()
throws
SQLException
{
return
cursor
.
get
();
}
public
int
getPos
()
{
return
cursor
.
getPos
();
}
public
SearchRow
getSearchRow
()
throws
SQLException
{
return
cursor
.
getSearchRow
();
}
public
boolean
next
()
throws
SQLException
{
while
(
true
)
{
if
(
cursor
==
null
)
{
nextCursor
();
if
(
cursor
==
null
)
{
return
false
;
}
}
if
(
cursor
.
next
())
{
return
true
;
}
cursor
=
null
;
}
}
private
void
nextCursor
()
throws
SQLException
{
if
(
inList
!=
null
)
{
if
(
inListIndex
<
inList
.
length
)
{
Value
v
=
inList
[
inListIndex
++];
find
(
v
);
}
}
else
if
(
inResult
!=
null
)
{
while
(
inResult
.
next
())
{
Value
v
=
inResult
.
currentRow
()[
0
];
v
=
v
.
convertTo
(
inColumn
.
getType
());
if
(
inResultTested
.
add
(
v
))
{
find
(
v
);
break
;
}
}
}
}
private
void
find
(
Value
v
)
throws
SQLException
{
v
=
v
.
convertTo
(
inColumn
.
getType
());
int
id
=
inColumn
.
getColumnId
();
if
(
start
==
null
)
{
start
=
table
.
getTemplateRow
();
}
start
.
setValue
(
id
,
v
);
cursor
=
index
.
find
(
session
,
start
,
start
);
}
public
boolean
previous
()
{
throw
Message
.
throwInternalError
();
}
}
h2/src/main/org/h2/table/MetaTable.java
浏览文件 @
18a3b3c2
...
...
@@ -854,6 +854,7 @@ public class MetaTable extends Table {
add
(
rows
,
new
String
[]{
"h2.objectCacheMaxPerElementSize"
,
""
+
SysProperties
.
OBJECT_CACHE_MAX_PER_ELEMENT_SIZE
});
add
(
rows
,
new
String
[]{
"h2.optimizeIn"
,
""
+
SysProperties
.
OPTIMIZE_IN
});
add
(
rows
,
new
String
[]{
"h2.optimizeInJoin"
,
""
+
SysProperties
.
optimizeInJoin
});
add
(
rows
,
new
String
[]{
"h2.optimizeInList"
,
""
+
SysProperties
.
OPTIMIZE_IN_LIST
});
add
(
rows
,
new
String
[]{
"h2.optimizeMinMax"
,
""
+
SysProperties
.
OPTIMIZE_MIN_MAX
});
add
(
rows
,
new
String
[]{
"h2.optimizeSubqueryCache"
,
""
+
SysProperties
.
OPTIMIZE_SUBQUERY_CACHE
});
add
(
rows
,
new
String
[]{
"h2.overflowExceptions"
,
""
+
SysProperties
.
OVERFLOW_EXCEPTIONS
});
...
...
h2/src/main/org/h2/table/TableFilter.java
浏览文件 @
18a3b3c2
...
...
@@ -16,13 +16,12 @@ import org.h2.engine.Session;
import
org.h2.expression.ConditionAndOr
;
import
org.h2.expression.Expression
;
import
org.h2.expression.ExpressionColumn
;
import
org.h2.index.Cursor
;
import
org.h2.index.Index
;
import
org.h2.index.IndexCondition
;
import
org.h2.index.IndexCursor
;
import
org.h2.message.Message
;
import
org.h2.result.Row
;
import
org.h2.result.SearchRow
;
import
org.h2.result.SortOrder
;
import
org.h2.util.ObjectArray
;
import
org.h2.util.StatementBuilder
;
import
org.h2.util.StringUtils
;
...
...
@@ -40,8 +39,6 @@ public class TableFilter implements ColumnResolver {
private
String
alias
;
private
Session
session
;
private
Index
index
;
private
IndexColumn
[]
indexColumns
;
private
Cursor
cursor
;
private
int
scanCount
;
/**
...
...
@@ -49,21 +46,31 @@ public class TableFilter implements ColumnResolver {
*/
private
boolean
used
;
// conditions that can be used for direct index lookup (start or end)
/**
* The filter used to walk through the index.
*/
private
final
IndexCursor
cursor
;
/**
* The index conditions used for direct index lookup (start or end).
*/
private
final
ObjectArray
<
IndexCondition
>
indexConditions
=
ObjectArray
.
newInstance
();
// conditions that can't be used for index lookup,
// but for row filter for this table (ID=ID, NAME LIKE '%X%')
/**
* Additional conditions that can't be used for index lookup,
* but for row filter for this table (ID=ID, NAME LIKE '%X%')
*/
private
Expression
filterCondition
;
// the complete join condition
/**
* The complete join condition.
*/
private
Expression
joinCondition
;
private
SearchRow
currentSearchRow
;
private
Row
current
;
private
int
state
;
private
TableFilter
join
;
private
boolean
outerJoin
;
private
ObjectArray
<
Column
>
naturalJoinColumns
;
private
boolean
foundOne
;
...
...
@@ -85,6 +92,7 @@ public class TableFilter implements ColumnResolver {
this
.
table
=
table
;
this
.
alias
=
alias
;
this
.
select
=
select
;
this
.
cursor
=
new
IndexCursor
(
session
);
if
(!
rightsChecked
)
{
session
.
getUser
().
checkRight
(
table
,
Right
.
SELECT
);
}
...
...
@@ -229,71 +237,17 @@ public class TableFilter implements ColumnResolver {
foundOne
=
false
;
}
private
Value
getMax
(
Value
a
,
Value
b
,
boolean
bigger
)
throws
SQLException
{
if
(
a
==
null
)
{
return
b
;
}
else
if
(
b
==
null
)
{
return
a
;
}
int
comp
=
a
.
compareTo
(
b
,
session
.
getDatabase
().
getCompareMode
());
if
(!
bigger
)
{
comp
=
-
comp
;
}
return
comp
>
0
?
a
:
b
;
}
/**
* Check if there are more rows to read.
*
* @return true if there are
*/
public
boolean
next
()
throws
SQLException
{
boolean
alwaysFalse
=
false
;
if
(
state
==
AFTER_LAST
)
{
return
false
;
}
else
if
(
state
==
BEFORE_FIRST
)
{
SearchRow
start
=
null
,
end
=
null
;
for
(
IndexCondition
condition
:
indexConditions
)
{
if
(
condition
.
isAlwaysFalse
())
{
alwaysFalse
=
true
;
break
;
}
Column
column
=
condition
.
getColumn
();
int
type
=
column
.
getType
();
int
id
=
column
.
getColumnId
();
Value
v
=
condition
.
getCurrentValue
(
session
).
convertTo
(
type
);
boolean
isStart
=
condition
.
isStart
(),
isEnd
=
condition
.
isEnd
();
IndexColumn
idxCol
=
indexColumns
[
id
];
if
(
idxCol
!=
null
&&
(
idxCol
.
sortType
&
SortOrder
.
DESCENDING
)
!=
0
)
{
// if the index column is sorted the other way, we swap end and start
// NULLS_FIRST / NULLS_LAST is not a problem, as nulls never match anyway
boolean
temp
=
isStart
;
isStart
=
isEnd
;
isEnd
=
temp
;
}
if
(
isStart
)
{
Value
newStart
;
if
(
start
==
null
)
{
start
=
table
.
getTemplateRow
();
newStart
=
v
;
}
else
{
newStart
=
getMax
(
start
.
getValue
(
id
),
v
,
true
);
}
start
.
setValue
(
id
,
newStart
);
}
if
(
isEnd
)
{
Value
newEnd
;
if
(
end
==
null
)
{
end
=
table
.
getTemplateRow
();
newEnd
=
v
;
}
else
{
newEnd
=
getMax
(
end
.
getValue
(
id
),
v
,
false
);
}
end
.
setValue
(
id
,
newEnd
);
}
}
if
(!
alwaysFalse
)
{
cursor
=
index
.
find
(
session
,
start
,
end
);
cursor
.
find
(
indexConditions
);
if
(!
cursor
.
isAlwaysFalse
())
{
if
(
join
!=
null
)
{
join
.
reset
();
}
...
...
@@ -310,7 +264,7 @@ public class TableFilter implements ColumnResolver {
if
(
state
==
NULL_ROW
)
{
break
;
}
if
(
alwaysFalse
)
{
if
(
cursor
.
isAlwaysFalse
()
)
{
state
=
AFTER_LAST
;
}
else
{
if
((++
scanCount
&
4095
)
==
0
)
{
...
...
@@ -319,7 +273,6 @@ public class TableFilter implements ColumnResolver {
if
(
cursor
.
next
())
{
currentSearchRow
=
cursor
.
getSearchRow
();
current
=
null
;
// cursor.get();
state
=
FOUND
;
}
else
{
state
=
AFTER_LAST
;
...
...
@@ -566,17 +519,7 @@ public class TableFilter implements ColumnResolver {
public
void
setIndex
(
Index
index
)
{
this
.
index
=
index
;
Column
[]
columns
=
table
.
getColumns
();
indexColumns
=
new
IndexColumn
[
columns
.
length
];
IndexColumn
[]
idxCols
=
index
.
getIndexColumns
();
if
(
idxCols
!=
null
)
{
for
(
int
i
=
0
;
i
<
columns
.
length
;
i
++)
{
int
idx
=
index
.
getColumnIndex
(
columns
[
i
]);
if
(
idx
>=
0
)
{
indexColumns
[
i
]
=
idxCols
[
idx
];
}
}
}
cursor
.
setIndex
(
index
);
}
public
void
setUsed
(
boolean
used
)
{
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论