Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
0f38abf2
提交
0f38abf2
authored
12月 21, 2018
作者:
Evgenij Ryazanov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Handle null elements in array and row values in comparison operations properly
上级
d5d927d2
隐藏空白字符变更
内嵌
并排
正在显示
13 个修改的文件
包含
391 行增加
和
72 行删除
+391
-72
Database.java
h2/src/main/org/h2/engine/Database.java
+20
-2
Comparison.java
h2/src/main/org/h2/expression/condition/Comparison.java
+75
-30
ConditionIn.java
h2/src/main/org/h2/expression/condition/ConditionIn.java
+6
-7
ConditionInConstantSet.java
...n/org/h2/expression/condition/ConditionInConstantSet.java
+16
-10
ConditionInParameter.java
...ain/org/h2/expression/condition/ConditionInParameter.java
+5
-7
ConditionInSelect.java
...c/main/org/h2/expression/condition/ConditionInSelect.java
+11
-14
LocalResult.java
h2/src/main/org/h2/result/LocalResult.java
+8
-0
LocalResultImpl.java
h2/src/main/org/h2/result/LocalResultImpl.java
+22
-0
Value.java
h2/src/main/org/h2/value/Value.java
+44
-2
ValueCollectionBase.java
h2/src/main/org/h2/value/ValueCollectionBase.java
+62
-0
ValueNull.java
h2/src/main/org/h2/value/ValueNull.java
+5
-0
array.sql
h2/src/test/org/h2/test/scripts/datatypes/array.sql
+54
-0
row.sql
h2/src/test/org/h2/test/scripts/datatypes/row.sql
+63
-0
没有找到文件。
h2/src/main/org/h2/engine/Database.java
浏览文件 @
0f38abf2
...
...
@@ -412,8 +412,8 @@ public class Database implements DataHandler {
}
/**
* Compare two values with the current comparison mode. The values may
not
*
be of the same type
.
* Compare two values with the current comparison mode. The values may
have
*
different data types including NULL
.
*
* @param a the first value
* @param b the second value
...
...
@@ -424,6 +424,24 @@ public class Database implements DataHandler {
return
a
.
compareTo
(
b
,
mode
,
compareMode
);
}
/**
* Compare two values with the current comparison mode. The values may have
* different data types including NULL.
*
* @param v the other value
* @param databaseMode the database mode
* @param compareMode the compare mode
* @param a the first value
* @param b the second value
* @param forEquality perform only check for equality (= or <>)
* @return 0 if both values are equal, -1 if the first value is smaller, 1
* if the second value is larger, {@link Integer#MIN_VALUE} if order
* is not defined due to NULL comparison
*/
public
int
compareWithNull
(
Value
a
,
Value
b
,
boolean
forEquality
)
{
return
a
.
compareWithNull
(
b
,
forEquality
,
mode
,
compareMode
);
}
/**
* Compare two values with the current comparison mode. The values must be
* of the same type.
...
...
h2/src/main/org/h2/expression/condition/Comparison.java
浏览文件 @
0f38abf2
...
...
@@ -283,22 +283,15 @@ public class Comparison extends Condition {
}
return
ValueBoolean
.
get
(
result
);
}
if
(
l
==
ValueNull
.
INSTANCE
)
{
if
((
compareType
&
NULL_SAFE
)
==
0
)
{
return
ValueNull
.
INSTANCE
;
}
}
Value
r
=
right
.
getValue
(
session
);
if
(
r
==
ValueNull
.
INSTANCE
)
{
if
((
compareType
&
NULL_SAFE
)
==
0
)
{
return
ValueNull
.
INSTANCE
;
}
// Optimization: do not evaluate right if not necessary
if
(
l
==
ValueNull
.
INSTANCE
&&
(
compareType
&
NULL_SAFE
)
==
0
)
{
return
ValueNull
.
INSTANCE
;
}
return
compare
NotNull
(
database
,
l
,
r
,
compareType
);
return
compare
(
database
,
l
,
right
.
getValue
(
session
)
,
compareType
);
}
/**
* Compare two values
, given the values are not NULL
.
* Compare two values.
*
* @param database the database
* @param l the first value
...
...
@@ -306,39 +299,91 @@ public class Comparison extends Condition {
* @param compareType the compare type
* @return result of comparison, either TRUE, FALSE, or NULL
*/
static
Value
compare
NotNull
(
Database
database
,
Value
l
,
Value
r
,
int
compareType
)
{
boolean
result
;
static
Value
compare
(
Database
database
,
Value
l
,
Value
r
,
int
compareType
)
{
Value
result
;
switch
(
compareType
)
{
case
EQUAL:
case
EQUAL:
{
int
cmp
=
database
.
compareWithNull
(
l
,
r
,
true
);
if
(
cmp
==
0
)
{
result
=
ValueBoolean
.
TRUE
;
}
else
if
(
cmp
==
Integer
.
MIN_VALUE
)
{
result
=
ValueNull
.
INSTANCE
;
}
else
{
result
=
ValueBoolean
.
FALSE
;
}
break
;
}
case
EQUAL_NULL_SAFE:
result
=
database
.
areEqual
(
l
,
r
);
result
=
ValueBoolean
.
get
(
database
.
areEqual
(
l
,
r
)
);
break
;
case
NOT_EQUAL:
case
NOT_EQUAL:
{
int
cmp
=
database
.
compareWithNull
(
l
,
r
,
true
);
if
(
cmp
==
0
)
{
result
=
ValueBoolean
.
FALSE
;
}
else
if
(
cmp
==
Integer
.
MIN_VALUE
)
{
result
=
ValueNull
.
INSTANCE
;
}
else
{
result
=
ValueBoolean
.
TRUE
;
}
break
;
}
case
NOT_EQUAL_NULL_SAFE:
result
=
!
database
.
areEqual
(
l
,
r
);
result
=
ValueBoolean
.
get
(!
database
.
areEqual
(
l
,
r
)
);
break
;
case
BIGGER_EQUAL:
result
=
database
.
compare
(
l
,
r
)
>=
0
;
case
BIGGER_EQUAL:
{
int
cmp
=
database
.
compareWithNull
(
l
,
r
,
false
);
if
(
cmp
>=
0
)
{
result
=
ValueBoolean
.
TRUE
;
}
else
if
(
cmp
==
Integer
.
MIN_VALUE
)
{
result
=
ValueNull
.
INSTANCE
;
}
else
{
result
=
ValueBoolean
.
FALSE
;
}
break
;
case
BIGGER:
result
=
database
.
compare
(
l
,
r
)
>
0
;
}
case
BIGGER:
{
int
cmp
=
database
.
compareWithNull
(
l
,
r
,
false
);
if
(
cmp
>
0
)
{
result
=
ValueBoolean
.
TRUE
;
}
else
if
(
cmp
==
Integer
.
MIN_VALUE
)
{
result
=
ValueNull
.
INSTANCE
;
}
else
{
result
=
ValueBoolean
.
FALSE
;
}
break
;
case
SMALLER_EQUAL:
result
=
database
.
compare
(
l
,
r
)
<=
0
;
}
case
SMALLER_EQUAL:
{
int
cmp
=
database
.
compareWithNull
(
l
,
r
,
false
);
if
(
cmp
==
Integer
.
MIN_VALUE
)
{
result
=
ValueNull
.
INSTANCE
;
}
else
{
result
=
ValueBoolean
.
get
(
cmp
<=
0
);
}
break
;
case
SMALLER:
result
=
database
.
compare
(
l
,
r
)
<
0
;
}
case
SMALLER:
{
int
cmp
=
database
.
compareWithNull
(
l
,
r
,
false
);
if
(
cmp
==
Integer
.
MIN_VALUE
)
{
result
=
ValueNull
.
INSTANCE
;
}
else
{
result
=
ValueBoolean
.
get
(
cmp
<
0
);
}
break
;
}
case
SPATIAL_INTERSECTS:
{
ValueGeometry
lg
=
(
ValueGeometry
)
l
.
convertTo
(
Value
.
GEOMETRY
);
ValueGeometry
rg
=
(
ValueGeometry
)
r
.
convertTo
(
Value
.
GEOMETRY
);
result
=
lg
.
intersectsBoundingBox
(
rg
);
if
(
l
==
ValueNull
.
INSTANCE
||
r
==
ValueNull
.
INSTANCE
)
{
result
=
ValueNull
.
INSTANCE
;
}
else
{
ValueGeometry
lg
=
(
ValueGeometry
)
l
.
convertTo
(
Value
.
GEOMETRY
);
ValueGeometry
rg
=
(
ValueGeometry
)
r
.
convertTo
(
Value
.
GEOMETRY
);
result
=
ValueBoolean
.
get
(
lg
.
intersectsBoundingBox
(
rg
));
}
break
;
}
default
:
throw
DbException
.
throwInternalError
(
"type="
+
compareType
);
}
return
ValueBoolean
.
get
(
result
)
;
return
result
;
}
private
int
getReversedCompareType
(
int
type
)
{
...
...
h2/src/main/org/h2/expression/condition/ConditionIn.java
浏览文件 @
0f38abf2
...
...
@@ -49,8 +49,8 @@ public class ConditionIn extends Condition {
@Override
public
Value
getValue
(
Session
session
)
{
Value
l
=
left
.
getValue
(
session
);
if
(
l
==
ValueNull
.
INSTANCE
)
{
return
l
;
if
(
l
.
containsNull
()
)
{
return
ValueNull
.
INSTANCE
;
}
int
size
=
valueList
.
size
();
if
(
size
==
1
)
{
...
...
@@ -63,9 +63,8 @@ public class ConditionIn extends Condition {
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
Expression
e
=
valueList
.
get
(
i
);
Value
r
=
e
.
getValue
(
session
);
Value
cmp
;
if
(
r
==
ValueNull
.
INSTANCE
||
(
cmp
=
Comparison
.
compareNotNull
(
database
,
l
,
r
,
Comparison
.
EQUAL
))
==
ValueNull
.
INSTANCE
)
{
Value
cmp
=
Comparison
.
compare
(
database
,
l
,
r
,
Comparison
.
EQUAL
);
if
(
cmp
==
ValueNull
.
INSTANCE
)
{
hasNull
=
true
;
}
else
if
(
cmp
==
ValueBoolean
.
TRUE
)
{
return
cmp
;
...
...
@@ -112,7 +111,7 @@ public class ConditionIn extends Condition {
ArrayList
<
Expression
>
list
=
new
ArrayList
<>(
ri
.
getRowCount
());
while
(
ri
.
next
())
{
Value
v
=
ri
.
currentRow
()[
0
];
if
(
v
!=
ValueNull
.
INSTANCE
)
{
if
(
!
v
.
containsNull
()
)
{
allValuesNull
=
false
;
}
list
.
add
(
ValueExpression
.
get
(
v
));
...
...
@@ -127,7 +126,7 @@ public class ConditionIn extends Condition {
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
Expression
e
=
valueList
.
get
(
i
);
e
=
e
.
optimize
(
session
);
if
(
e
.
isConstant
()
&&
e
.
getValue
(
session
)
!=
ValueNull
.
INSTANCE
)
{
if
(
e
.
isConstant
()
&&
!
e
.
getValue
(
session
).
containsNull
()
)
{
allValuesNull
=
false
;
}
if
(
allValuesConstant
&&
!
e
.
isConstant
())
{
...
...
h2/src/main/org/h2/expression/condition/ConditionInConstantSet.java
浏览文件 @
0f38abf2
...
...
@@ -35,6 +35,7 @@ public class ConditionInConstantSet extends Condition {
private
Expression
left
;
private
final
ArrayList
<
Expression
>
valueList
;
private
final
TreeSet
<
Value
>
valueSet
;
private
boolean
hasNull
;
private
final
int
type
;
private
ExtTypeInfo
extTypeInfo
;
...
...
@@ -58,27 +59,32 @@ public class ConditionInConstantSet extends Condition {
if
(
type
==
Value
.
ENUM
)
{
extTypeInfo
=
((
ExpressionColumn
)
left
).
getColumn
().
getExtTypeInfo
();
for
(
Expression
expression
:
valueList
)
{
valueSet
.
add
(
extTypeInfo
.
cast
(
expression
.
getValue
(
session
)));
add
(
extTypeInfo
.
cast
(
expression
.
getValue
(
session
)));
}
}
else
{
for
(
Expression
expression
:
valueList
)
{
valueSet
.
add
(
expression
.
getValue
(
session
).
convertTo
(
type
,
mode
));
add
(
expression
.
getValue
(
session
).
convertTo
(
type
,
mode
));
}
}
}
private
void
add
(
Value
v
)
{
if
(
v
.
containsNull
())
{
hasNull
=
true
;
}
else
{
valueSet
.
add
(
v
);
}
}
@Override
public
Value
getValue
(
Session
session
)
{
Value
x
=
left
.
getValue
(
session
);
if
(
x
==
ValueNull
.
INSTANCE
)
{
if
(
x
.
containsNull
()
)
{
return
x
;
}
boolean
result
=
valueSet
.
contains
(
x
);
if
(!
result
)
{
boolean
setHasNull
=
valueSet
.
contains
(
ValueNull
.
INSTANCE
);
if
(
setHasNull
)
{
return
ValueNull
.
INSTANCE
;
}
if
(!
result
&&
hasNull
)
{
return
ValueNull
.
INSTANCE
;
}
return
ValueBoolean
.
get
(
result
);
}
...
...
@@ -168,9 +174,9 @@ public class ConditionInConstantSet extends Condition {
if
(
add
.
isConstant
())
{
valueList
.
add
(
add
);
if
(
type
==
Value
.
ENUM
)
{
valueSet
.
add
(
add
.
getValue
(
session
).
convertToEnum
(
extTypeInfo
));
add
(
add
.
getValue
(
session
).
convertToEnum
(
extTypeInfo
));
}
else
{
valueSet
.
add
(
add
.
getValue
(
session
).
convertTo
(
type
,
session
.
getDatabase
().
getMode
()));
add
(
add
.
getValue
(
session
).
convertTo
(
type
,
session
.
getDatabase
().
getMode
()));
}
return
this
;
}
...
...
h2/src/main/org/h2/expression/condition/ConditionInParameter.java
浏览文件 @
0f38abf2
...
...
@@ -67,14 +67,13 @@ public class ConditionInParameter extends Condition {
static
Value
getValue
(
Database
database
,
Value
l
,
Value
value
)
{
boolean
hasNull
=
false
;
if
(
value
==
ValueNull
.
INSTANCE
)
{
if
(
value
.
containsNull
()
)
{
hasNull
=
true
;
}
else
if
(
value
.
getType
()
==
Value
.
RESULT_SET
)
{
for
(
ResultInterface
ri
=
value
.
getResult
();
ri
.
next
();)
{
Value
r
=
ri
.
currentRow
()[
0
];
Value
cmp
;
if
(
r
==
ValueNull
.
INSTANCE
||
(
cmp
=
Comparison
.
compareNotNull
(
database
,
l
,
r
,
Comparison
.
EQUAL
))
==
ValueNull
.
INSTANCE
)
{
Value
cmp
=
Comparison
.
compare
(
database
,
l
,
r
,
Comparison
.
EQUAL
);
if
(
cmp
==
ValueNull
.
INSTANCE
)
{
hasNull
=
true
;
}
else
if
(
cmp
==
ValueBoolean
.
TRUE
)
{
return
cmp
;
...
...
@@ -82,9 +81,8 @@ public class ConditionInParameter extends Condition {
}
}
else
{
for
(
Value
r
:
((
ValueArray
)
value
.
convertTo
(
Value
.
ARRAY
)).
getList
())
{
Value
cmp
;
if
(
r
==
ValueNull
.
INSTANCE
||
(
cmp
=
Comparison
.
compareNotNull
(
database
,
l
,
r
,
Comparison
.
EQUAL
))
==
ValueNull
.
INSTANCE
)
{
Value
cmp
=
Comparison
.
compare
(
database
,
l
,
r
,
Comparison
.
EQUAL
);
if
(
cmp
==
ValueNull
.
INSTANCE
)
{
hasNull
=
true
;
}
else
if
(
cmp
==
ValueBoolean
.
TRUE
)
{
return
cmp
;
...
...
h2/src/main/org/h2/expression/condition/ConditionInSelect.java
浏览文件 @
0f38abf2
...
...
@@ -18,7 +18,6 @@ import org.h2.table.ColumnResolver;
import
org.h2.table.TableFilter
;
import
org.h2.util.StringUtils
;
import
org.h2.value.Value
;
import
org.h2.value.ValueArray
;
import
org.h2.value.ValueBoolean
;
import
org.h2.value.ValueNull
;
import
org.h2.value.ValueRow
;
...
...
@@ -53,8 +52,8 @@ public class ConditionInSelect extends Condition {
Value
l
=
left
.
getValue
(
session
);
if
(!
rows
.
hasNext
())
{
return
ValueBoolean
.
get
(
all
);
}
else
if
(
l
==
ValueNull
.
INSTANCE
)
{
return
l
;
}
else
if
(
l
.
containsNull
()
)
{
return
ValueNull
.
INSTANCE
;
}
if
(!
database
.
getSettings
().
optimizeInSelect
)
{
return
getValueSlow
(
rows
,
l
);
...
...
@@ -65,8 +64,8 @@ public class ConditionInSelect extends Condition {
}
int
columnCount
=
query
.
getColumnCount
();
if
(
columnCount
!=
1
)
{
l
=
l
.
convertTo
(
Value
.
ARRAY
);
Value
[]
leftValue
=
((
Value
Array
)
l
).
getList
();
l
=
l
.
convertTo
(
Value
.
ROW
);
Value
[]
leftValue
=
((
Value
Row
)
l
).
getList
();
if
(
columnCount
==
leftValue
.
length
&&
rows
.
containsDistinct
(
leftValue
))
{
return
ValueBoolean
.
TRUE
;
}
...
...
@@ -79,9 +78,9 @@ public class ConditionInSelect extends Condition {
if
(
rows
.
containsDistinct
(
new
Value
[]
{
l
}))
{
return
ValueBoolean
.
TRUE
;
}
if
(
rows
.
containsDistinct
(
new
Value
[]
{
ValueNull
.
INSTANCE
}))
{
return
ValueNull
.
INSTANCE
;
}
}
if
(
rows
.
containsNull
())
{
return
ValueNull
.
INSTANCE
;
}
return
ValueBoolean
.
FALSE
;
}
...
...
@@ -93,9 +92,8 @@ public class ConditionInSelect extends Condition {
while
(
rows
.
next
())
{
Value
[]
currentRow
=
rows
.
currentRow
();
Value
r
=
query
.
getColumnCount
()
==
1
?
currentRow
[
0
]
:
ValueRow
.
get
(
currentRow
);
Value
cmp
;
if
(
r
==
ValueNull
.
INSTANCE
||
(
cmp
=
Comparison
.
compareNotNull
(
database
,
l
,
r
,
compareType
))
==
ValueNull
.
INSTANCE
)
{
Value
cmp
=
Comparison
.
compare
(
database
,
l
,
r
,
compareType
);
if
(
cmp
==
ValueNull
.
INSTANCE
)
{
return
ValueNull
.
INSTANCE
;
}
else
if
(
cmp
==
ValueBoolean
.
FALSE
)
{
return
cmp
;
...
...
@@ -107,9 +105,8 @@ public class ConditionInSelect extends Condition {
while
(
rows
.
next
())
{
Value
[]
currentRow
=
rows
.
currentRow
();
Value
r
=
query
.
getColumnCount
()
==
1
?
currentRow
[
0
]
:
ValueRow
.
get
(
currentRow
);
Value
cmp
;
if
(
r
==
ValueNull
.
INSTANCE
||
(
cmp
=
Comparison
.
compareNotNull
(
database
,
l
,
r
,
compareType
))
==
ValueNull
.
INSTANCE
)
{
Value
cmp
=
Comparison
.
compare
(
database
,
l
,
r
,
compareType
);
if
(
cmp
==
ValueNull
.
INSTANCE
)
{
hasNull
=
true
;
}
else
if
(
cmp
==
ValueBoolean
.
TRUE
)
{
return
cmp
;
...
...
h2/src/main/org/h2/result/LocalResult.java
浏览文件 @
0f38abf2
...
...
@@ -49,6 +49,14 @@ public interface LocalResult extends ResultInterface, ResultTarget {
*/
boolean
containsDistinct
(
Value
[]
values
);
/**
* Check if this result set contains a NULL value. This method may reset
* this result.
*
* @return true if there is a NULL value
*/
boolean
containsNull
();
/**
* Remove the row from the result set if it exists.
*
...
...
h2/src/main/org/h2/result/LocalResultImpl.java
浏览文件 @
0f38abf2
...
...
@@ -45,6 +45,7 @@ public class LocalResultImpl implements LocalResult {
private
int
[]
distinctIndexes
;
private
boolean
closed
;
private
boolean
containsLobs
;
private
Boolean
containsNull
;
/**
* Construct a local result object.
...
...
@@ -212,6 +213,27 @@ public class LocalResultImpl implements LocalResult {
return
distinctRows
.
get
(
array
)
!=
null
;
}
@Override
public
boolean
containsNull
()
{
Boolean
r
=
containsNull
;
if
(
r
==
null
)
{
r
=
false
;
reset
();
while
(
next
())
{
Value
[]
row
=
currentRow
;
for
(
int
i
=
0
;
i
<
visibleColumnCount
;
i
++)
{
if
(
row
[
i
].
containsNull
())
{
r
=
true
;
break
;
}
}
}
reset
();
containsNull
=
r
;
}
return
r
;
}
@Override
public
void
reset
()
{
rowId
=
-
1
;
...
...
h2/src/main/org/h2/value/Value.java
浏览文件 @
0f38abf2
...
...
@@ -1347,7 +1347,7 @@ public abstract class Value {
return
ValueResultSet
.
get
(
result
);
}
private
DbException
getDataConversionError
(
int
targetType
)
{
DbException
getDataConversionError
(
int
targetType
)
{
DataType
from
=
DataType
.
getDataType
(
getType
());
DataType
to
=
DataType
.
getDataType
(
targetType
);
throw
DbException
.
get
(
ErrorCode
.
DATA_CONVERSION_ERROR_1
,
(
from
!=
null
?
from
.
name
:
"type="
+
getType
())
...
...
@@ -1372,7 +1372,7 @@ public abstract class Value {
* @param v the other value
* @param databaseMode the database mode
* @param compareMode the compare mode
* @return 0 if both values are equal, -1 if th
e other
value is smaller, and
* @return 0 if both values are equal, -1 if th
is
value is smaller, and
* 1 otherwise
*/
public
final
int
compareTo
(
Value
v
,
Mode
databaseMode
,
CompareMode
compareMode
)
{
...
...
@@ -1401,6 +1401,48 @@ public abstract class Value {
return
l
.
compareTypeSafe
(
v
,
compareMode
);
}
/**
* Compare this value against another value using the specified compare
* mode.
*
* @param v the other value
* @param forEquality perform only check for equality
* @param databaseMode the database mode
* @param compareMode the compare mode
* @return 0 if both values are equal, -1 if this value is smaller, 1
* if other value is larger, {@link Integer#MIN_VALUE} if order is
* not defined due to NULL comparison
*/
public
int
compareWithNull
(
Value
v
,
boolean
forEquality
,
Mode
databaseMode
,
CompareMode
compareMode
)
{
if
(
this
==
ValueNull
.
INSTANCE
||
v
==
ValueNull
.
INSTANCE
)
{
return
Integer
.
MIN_VALUE
;
}
Value
l
=
this
;
int
leftType
=
l
.
getType
();
int
rightType
=
v
.
getType
();
if
(
leftType
!=
rightType
||
leftType
==
Value
.
ENUM
)
{
int
dataType
=
Value
.
getHigherOrder
(
leftType
,
rightType
);
if
(
dataType
==
Value
.
ENUM
)
{
ExtTypeInfoEnum
enumerators
=
ExtTypeInfoEnum
.
getEnumeratorsForBinaryOperation
(
l
,
v
);
l
=
l
.
convertToEnum
(
enumerators
);
v
=
v
.
convertToEnum
(
enumerators
);
}
else
{
l
=
l
.
convertTo
(
dataType
,
databaseMode
);
v
=
v
.
convertTo
(
dataType
,
databaseMode
);
}
}
return
l
.
compareTypeSafe
(
v
,
compareMode
);
}
/**
* Returns true if this value is NULL or contains NULL value.
*
* @return true if this value is NULL or contains NULL value
*/
public
boolean
containsNull
()
{
return
false
;
}
public
int
getScale
()
{
return
0
;
}
...
...
h2/src/main/org/h2/value/ValueCollectionBase.java
浏览文件 @
0f38abf2
...
...
@@ -5,7 +5,10 @@
*/
package
org
.
h2
.
value
;
import
org.h2.api.ErrorCode
;
import
org.h2.engine.Constants
;
import
org.h2.engine.Mode
;
import
org.h2.message.DbException
;
import
org.h2.util.MathUtils
;
/**
...
...
@@ -52,6 +55,65 @@ abstract class ValueCollectionBase extends Value {
return
MathUtils
.
convertLongToInt
(
size
);
}
@Override
public
int
compareWithNull
(
Value
v
,
boolean
forEquality
,
Mode
databaseMode
,
CompareMode
compareMode
)
{
if
(
v
==
ValueNull
.
INSTANCE
)
{
return
Integer
.
MIN_VALUE
;
}
ValueCollectionBase
l
=
this
;
int
leftType
=
l
.
getType
();
int
rightType
=
v
.
getType
();
if
(
rightType
!=
ARRAY
&&
rightType
!=
ROW
)
{
throw
getDataConversionError
(
leftType
);
}
ValueCollectionBase
r
=
(
ValueCollectionBase
)
v
;
Value
[]
leftArray
=
l
.
values
,
rightArray
=
r
.
values
;
int
leftLength
=
leftArray
.
length
,
rightLength
=
rightArray
.
length
;
if
(
leftLength
!=
rightLength
)
{
if
(
leftType
==
ROW
||
rightType
==
ROW
)
{
throw
DbException
.
get
(
ErrorCode
.
COLUMN_COUNT_DOES_NOT_MATCH
);
}
if
(
forEquality
)
{
return
1
;
}
}
if
(
forEquality
)
{
boolean
hasNull
=
false
;
for
(
int
i
=
0
;
i
<
leftLength
;
i
++)
{
Value
v1
=
leftArray
[
i
];
Value
v2
=
rightArray
[
i
];
int
comp
=
v1
.
compareWithNull
(
v2
,
forEquality
,
databaseMode
,
compareMode
);
if
(
comp
!=
0
)
{
if
(
comp
!=
Integer
.
MIN_VALUE
)
{
return
comp
;
}
hasNull
=
true
;
}
}
return
hasNull
?
Integer
.
MIN_VALUE
:
0
;
}
int
len
=
Math
.
min
(
leftLength
,
rightLength
);
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
Value
v1
=
leftArray
[
i
];
Value
v2
=
rightArray
[
i
];
int
comp
=
v1
.
compareWithNull
(
v2
,
forEquality
,
databaseMode
,
compareMode
);
if
(
comp
!=
0
)
{
return
comp
;
}
}
return
Integer
.
compare
(
leftLength
,
rightLength
);
}
@Override
public
boolean
containsNull
()
{
for
(
Value
v
:
values
)
{
if
(
v
.
containsNull
())
{
return
true
;
}
}
return
false
;
}
@Override
public
int
getMemory
()
{
int
memory
=
32
;
...
...
h2/src/main/org/h2/value/ValueNull.java
浏览文件 @
0f38abf2
...
...
@@ -143,6 +143,11 @@ public class ValueNull extends Value {
throw
DbException
.
throwInternalError
(
"compare null"
);
}
@Override
public
boolean
containsNull
()
{
return
true
;
}
@Override
public
long
getPrecision
()
{
return
PRECISION
;
...
...
h2/src/test/org/h2/test/scripts/datatypes/array.sql
浏览文件 @
0f38abf2
...
...
@@ -23,3 +23,57 @@ SELECT ARRAY[10];
SELECT
ARRAY
[
10
,
20
,
30
];
>>
[
10
,
20
,
30
]
SELECT
ARRAY
[
1
,
NULL
]
IS
NOT
DISTINCT
FROM
ARRAY
[
1
,
NULL
];
>>
TRUE
SELECT
ARRAY
[
1
,
NULL
]
IS
DISTINCT
FROM
ARRAY
[
1
,
NULL
];
>>
FALSE
SELECT
ARRAY
[
1
,
NULL
]
=
ARRAY
[
1
,
NULL
];
>>
null
SELECT
ARRAY
[
1
,
NULL
]
<>
ARRAY
[
1
,
NULL
];
>>
null
SELECT
ARRAY
[
NULL
]
=
ARRAY
[
NULL
,
NULL
];
>>
FALSE
select
ARRAY
[
1
,
NULL
,
2
]
=
ARRAY
[
1
,
NULL
,
1
];
>>
FALSE
select
ARRAY
[
1
,
NULL
,
2
]
<>
ARRAY
[
1
,
NULL
,
1
];
>>
TRUE
SELECT
ARRAY
[
1
,
NULL
]
>
ARRAY
[
1
,
NULL
];
>>
null
SELECT
ARRAY
[
1
,
2
]
>
ARRAY
[
1
,
NULL
];
>>
null
SELECT
ARRAY
[
1
,
2
,
NULL
]
>
ARRAY
[
1
,
1
,
NULL
];
>>
TRUE
SELECT
ARRAY
[
1
,
1
,
NULL
]
>
ARRAY
[
1
,
2
,
NULL
];
>>
FALSE
SELECT
ARRAY
[
1
,
2
,
NULL
]
<
ARRAY
[
1
,
1
,
NULL
];
>>
FALSE
SELECT
ARRAY
[
1
,
1
,
NULL
]
<=
ARRAY
[
1
,
1
,
NULL
];
>>
null
SELECT
ARRAY
[
1
,
NULL
]
IN
(
ARRAY
[
1
,
NULL
]);
>>
null
CREATE
TABLE
TEST
(
A
ARRAY
);
>
ok
INSERT
INTO
TEST
VALUES
(
ARRAY
[
1
,
NULL
]),
(
ARRAY
[
1
,
2
]);
>
update
count
:
2
SELECT
ARRAY
[
1
,
NULL
]
IN
(
SELECT
A
FROM
TEST
);
>>
null
DROP
TABLE
TEST
;
>
ok
h2/src/test/org/h2/test/scripts/datatypes/row.sql
浏览文件 @
0f38abf2
...
...
@@ -8,3 +8,66 @@ SELECT ROW (10);
SELECT
(
10
,
20
,
30
);
>>
ROW
(
10
,
20
,
30
)
SELECT
(
1
,
NULL
)
IS
NOT
DISTINCT
FROM
(
1
,
NULL
);
>>
TRUE
SELECT
(
1
,
NULL
)
IS
DISTINCT
FROM
ROW
(
1
,
NULL
);
>>
FALSE
SELECT
(
1
,
NULL
)
=
(
1
,
NULL
);
>>
null
SELECT
(
1
,
NULL
)
<>
(
1
,
NULL
);
>>
null
SELECT
ROW
(
NULL
)
=
(
NULL
,
NULL
);
>
exception
COLUMN_COUNT_DOES_NOT_MATCH
select
(
1
,
NULL
,
2
)
=
(
1
,
NULL
,
1
);
>>
FALSE
select
(
1
,
NULL
,
2
)
<>
(
1
,
NULL
,
1
);
>>
TRUE
SELECT
(
1
,
NULL
)
>
(
1
,
NULL
);
>>
null
SELECT
(
1
,
2
)
>
(
1
,
NULL
);
>>
null
SELECT
(
1
,
2
,
NULL
)
>
(
1
,
1
,
NULL
);
>>
TRUE
SELECT
(
1
,
1
,
NULL
)
>
(
1
,
2
,
NULL
);
>>
FALSE
SELECT
(
1
,
2
,
NULL
)
<
(
1
,
1
,
NULL
);
>>
FALSE
SELECT
(
1
,
1
,
NULL
)
<=
(
1
,
1
,
NULL
);
>>
null
SELECT
(
1
,
2
)
IN
(
SELECT
1
,
2
);
>>
TRUE
SELECT
(
1
,
2
)
IN
(
SELECT
*
FROM
VALUES
(
1
,
2
),
(
1
,
NULL
));
>>
TRUE
SELECT
(
1
,
2
)
IN
(
SELECT
*
FROM
VALUES
(
1
,
1
),
(
1
,
NULL
));
>>
null
SELECT
(
1
,
2
)
IN
(
SELECT
*
FROM
VALUES
(
1
,
1
),
(
1
,
3
));
>>
FALSE
SELECT
(
1
,
NULL
)
IN
(
SELECT
1
,
NULL
);
>>
null
SELECT
(
1
,
ARRAY
[
1
])
IN
(
SELECT
1
,
ARRAY
[
1
]);
>>
TRUE
SELECT
(
1
,
ARRAY
[
1
])
IN
(
SELECT
1
,
ARRAY
[
2
]);
>>
FALSE
SELECT
(
1
,
ARRAY
[
NULL
])
IN
(
SELECT
1
,
ARRAY
[
NULL
]);
>>
null
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论