Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
a22f1ea3
Unverified
提交
a22f1ea3
authored
12月 21, 2018
作者:
Evgenij Ryazanov
提交者:
GitHub
12月 21, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #1611 from katzyn/row
Handle null elements in array and row values in comparison operations properly
上级
eeace0e1
6bc29540
隐藏空白字符变更
内嵌
并排
正在显示
20 个修改的文件
包含
535 行增加
和
208 行删除
+535
-208
Database.java
h2/src/main/org/h2/engine/Database.java
+20
-2
Comparison.java
h2/src/main/org/h2/expression/condition/Comparison.java
+75
-32
ConditionIn.java
h2/src/main/org/h2/expression/condition/ConditionIn.java
+10
-13
ConditionInConstantSet.java
...n/org/h2/expression/condition/ConditionInConstantSet.java
+16
-10
ConditionInParameter.java
...ain/org/h2/expression/condition/ConditionInParameter.java
+11
-16
ConditionInSelect.java
...c/main/org/h2/expression/condition/ConditionInSelect.java
+41
-26
LocalResult.java
h2/src/main/org/h2/result/LocalResult.java
+8
-0
LocalResultImpl.java
h2/src/main/org/h2/result/LocalResultImpl.java
+23
-0
Value.java
h2/src/main/org/h2/value/Value.java
+44
-2
ValueArray.java
h2/src/main/org/h2/value/ValueArray.java
+2
-46
ValueCollectionBase.java
h2/src/main/org/h2/value/ValueCollectionBase.java
+126
-0
ValueNull.java
h2/src/main/org/h2/value/ValueNull.java
+5
-0
ValueRow.java
h2/src/main/org/h2/value/ValueRow.java
+2
-47
TestAll.java
h2/src/test/org/h2/test/TestAll.java
+1
-1
TestSubqueryPerformanceOnLazyExecutionMode.java
...2/test/db/TestSubqueryPerformanceOnLazyExecutionMode.java
+6
-1
array.sql
h2/src/test/org/h2/test/scripts/datatypes/array.sql
+63
-0
row.sql
h2/src/test/org/h2/test/scripts/datatypes/row.sql
+63
-0
select.sql
h2/src/test/org/h2/test/scripts/dml/select.sql
+5
-2
TestNestedJoins.java
h2/src/test/org/h2/test/synth/TestNestedJoins.java
+7
-5
TestOuterJoins.java
h2/src/test/org/h2/test/synth/TestOuterJoins.java
+7
-5
没有找到文件。
h2/src/main/org/h2/engine/Database.java
浏览文件 @
a22f1ea3
...
...
@@ -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
浏览文件 @
a22f1ea3
...
...
@@ -283,58 +283,101 @@ 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
ValueBoolean
.
get
(
compareNotNull
(
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
* @param r the second value
* @param compareType the compare type
* @return true if the comparison indicated by the comparison type evaluates
* to true
* @return result of comparison, either TRUE, FALSE, or NULL
*/
static
boolean
compareNotNull
(
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
:
...
...
h2/src/main/org/h2/expression/condition/ConditionIn.java
浏览文件 @
a22f1ea3
...
...
@@ -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
)
{
...
...
@@ -59,24 +59,21 @@ public class ConditionIn extends Condition {
return
ConditionInParameter
.
getValue
(
database
,
l
,
e
.
getValue
(
session
));
}
}
boolean
result
=
false
;
boolean
hasNull
=
false
;
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
Expression
e
=
valueList
.
get
(
i
);
Value
r
=
e
.
getValue
(
session
);
if
(
r
==
ValueNull
.
INSTANCE
)
{
Value
cmp
=
Comparison
.
compare
(
database
,
l
,
r
,
Comparison
.
EQUAL
);
if
(
cmp
==
ValueNull
.
INSTANCE
)
{
hasNull
=
true
;
}
else
{
result
=
Comparison
.
compareNotNull
(
database
,
l
,
r
,
Comparison
.
EQUAL
);
if
(
result
)
{
break
;
}
}
else
if
(
cmp
==
ValueBoolean
.
TRUE
)
{
return
cmp
;
}
}
if
(
!
result
&&
hasNull
)
{
if
(
hasNull
)
{
return
ValueNull
.
INSTANCE
;
}
return
ValueBoolean
.
get
(
result
)
;
return
ValueBoolean
.
FALSE
;
}
@Override
...
...
@@ -114,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
));
...
...
@@ -129,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
浏览文件 @
a22f1ea3
...
...
@@ -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
浏览文件 @
a22f1ea3
...
...
@@ -66,38 +66,33 @@ public class ConditionInParameter extends Condition {
private
final
Parameter
parameter
;
static
Value
getValue
(
Database
database
,
Value
l
,
Value
value
)
{
boolean
result
=
false
;
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
];
if
(
r
==
ValueNull
.
INSTANCE
)
{
Value
cmp
=
Comparison
.
compare
(
database
,
l
,
r
,
Comparison
.
EQUAL
);
if
(
cmp
==
ValueNull
.
INSTANCE
)
{
hasNull
=
true
;
}
else
{
result
=
Comparison
.
compareNotNull
(
database
,
l
,
r
,
Comparison
.
EQUAL
);
if
(
result
)
{
break
;
}
}
else
if
(
cmp
==
ValueBoolean
.
TRUE
)
{
return
cmp
;
}
}
}
else
{
for
(
Value
r
:
((
ValueArray
)
value
.
convertTo
(
Value
.
ARRAY
)).
getList
())
{
if
(
r
==
ValueNull
.
INSTANCE
)
{
Value
cmp
=
Comparison
.
compare
(
database
,
l
,
r
,
Comparison
.
EQUAL
);
if
(
cmp
==
ValueNull
.
INSTANCE
)
{
hasNull
=
true
;
}
else
{
result
=
Comparison
.
compareNotNull
(
database
,
l
,
r
,
Comparison
.
EQUAL
);
if
(
result
)
{
break
;
}
}
else
if
(
cmp
==
ValueBoolean
.
TRUE
)
{
return
cmp
;
}
}
}
if
(
!
result
&&
hasNull
)
{
if
(
hasNull
)
{
return
ValueNull
.
INSTANCE
;
}
return
ValueBoolean
.
get
(
result
)
;
return
ValueBoolean
.
FALSE
;
}
/**
...
...
h2/src/main/org/h2/expression/condition/ConditionInSelect.java
浏览文件 @
a22f1ea3
...
...
@@ -5,6 +5,7 @@
*/
package
org
.
h2
.
expression
.
condition
;
import
org.h2.api.ErrorCode
;
import
org.h2.command.dml.Query
;
import
org.h2.engine.Database
;
import
org.h2.engine.Session
;
...
...
@@ -12,15 +13,16 @@ import org.h2.expression.Expression;
import
org.h2.expression.ExpressionColumn
;
import
org.h2.expression.ExpressionVisitor
;
import
org.h2.index.IndexCondition
;
import
org.h2.message.DbException
;
import
org.h2.result.LocalResult
;
import
org.h2.result.ResultInterface
;
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
;
/**
* An 'in' condition with a subquery, as in WHERE ID IN(SELECT ...)
...
...
@@ -52,8 +54,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
);
...
...
@@ -64,8 +66,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
;
}
...
...
@@ -74,13 +76,20 @@ public class ConditionInSelect extends Condition {
if
(
dataType
==
Value
.
NULL
)
{
return
ValueBoolean
.
FALSE
;
}
if
(
l
.
getType
()
==
Value
.
ROW
)
{
Value
[]
leftList
=
((
ValueRow
)
l
).
getList
();
if
(
leftList
.
length
!=
1
)
{
throw
DbException
.
get
(
ErrorCode
.
COLUMN_COUNT_DOES_NOT_MATCH
);
}
l
=
leftList
[
0
];
}
l
=
l
.
convertTo
(
dataType
,
database
.
getMode
());
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
;
}
...
...
@@ -89,29 +98,35 @@ public class ConditionInSelect extends Condition {
// this only returns the correct result if the result has at least one
// row, and if l is not null
boolean
hasNull
=
false
;
boolean
result
=
all
;
while
(
rows
.
next
())
{
boolean
value
;
Value
[]
currentRow
=
rows
.
currentRow
();
Value
r
=
query
.
getColumnCount
()
==
1
?
currentRow
[
0
]
:
org
.
h2
.
value
.
ValueArray
.
get
(
currentRow
);
if
(
r
==
ValueNull
.
INSTANCE
)
{
value
=
false
;
hasNull
=
true
;
}
else
{
value
=
Comparison
.
compareNotNull
(
database
,
l
,
r
,
compareType
);
if
(
all
)
{
while
(
rows
.
next
())
{
Value
cmp
=
compare
(
l
,
rows
);
if
(
cmp
==
ValueNull
.
INSTANCE
)
{
hasNull
=
true
;
}
else
if
(
cmp
==
ValueBoolean
.
FALSE
)
{
return
cmp
;
}
}
if
(!
value
&&
all
)
{
result
=
false
;
break
;
}
else
if
(
value
&&
!
all
)
{
result
=
true
;
break
;
}
else
{
while
(
rows
.
next
())
{
Value
cmp
=
compare
(
l
,
rows
);
if
(
cmp
==
ValueNull
.
INSTANCE
)
{
hasNull
=
true
;
}
else
if
(
cmp
==
ValueBoolean
.
TRUE
)
{
return
cmp
;
}
}
}
if
(
!
result
&&
hasNull
)
{
if
(
hasNull
)
{
return
ValueNull
.
INSTANCE
;
}
return
ValueBoolean
.
get
(
result
);
return
ValueBoolean
.
get
(
all
);
}
private
Value
compare
(
Value
l
,
ResultInterface
rows
)
{
Value
[]
currentRow
=
rows
.
currentRow
();
Value
r
=
l
.
getType
()
!=
Value
.
ROW
&&
query
.
getColumnCount
()
==
1
?
currentRow
[
0
]
:
ValueRow
.
get
(
currentRow
);
return
Comparison
.
compare
(
database
,
l
,
r
,
compareType
);
}
@Override
...
...
h2/src/main/org/h2/result/LocalResult.java
浏览文件 @
a22f1ea3
...
...
@@ -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
浏览文件 @
a22f1ea3
...
...
@@ -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.
...
...
@@ -127,6 +128,7 @@ public class LocalResultImpl implements LocalResult {
copy
.
offset
=
0
;
copy
.
limit
=
-
1
;
copy
.
external
=
e2
;
copy
.
containsNull
=
containsNull
;
return
copy
;
}
...
...
@@ -212,6 +214,27 @@ public class LocalResultImpl implements LocalResult {
return
distinctRows
.
get
(
array
)
!=
null
;
}
@Override
public
boolean
containsNull
()
{
Boolean
r
=
containsNull
;
if
(
r
==
null
)
{
r
=
false
;
reset
();
loop:
while
(
next
())
{
Value
[]
row
=
currentRow
;
for
(
int
i
=
0
;
i
<
visibleColumnCount
;
i
++)
{
if
(
row
[
i
].
containsNull
())
{
r
=
true
;
break
loop
;
}
}
}
reset
();
containsNull
=
r
;
}
return
r
;
}
@Override
public
void
reset
()
{
rowId
=
-
1
;
...
...
h2/src/main/org/h2/value/Value.java
浏览文件 @
a22f1ea3
...
...
@@ -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/ValueArray.java
浏览文件 @
a22f1ea3
...
...
@@ -10,14 +10,12 @@ import java.sql.PreparedStatement;
import
java.sql.SQLException
;
import
java.util.Arrays
;
import
org.h2.engine.Constants
;
import
org.h2.engine.SysProperties
;
import
org.h2.util.MathUtils
;
/**
* Implementation of the ARRAY data type.
*/
public
class
ValueArray
extends
Value
{
public
class
ValueArray
extends
Value
CollectionBase
{
/**
* Empty array.
...
...
@@ -25,12 +23,10 @@ public class ValueArray extends Value {
private
static
final
Object
EMPTY
=
get
(
new
Value
[
0
]);
private
final
Class
<?>
componentType
;
private
final
Value
[]
values
;
private
int
hash
;
private
ValueArray
(
Class
<?>
componentType
,
Value
[]
list
)
{
super
(
list
);
this
.
componentType
=
componentType
;
this
.
values
=
list
;
}
/**
...
...
@@ -65,19 +61,6 @@ public class ValueArray extends Value {
return
(
ValueArray
)
EMPTY
;
}
@Override
public
int
hashCode
()
{
if
(
hash
!=
0
)
{
return
hash
;
}
int
h
=
1
;
for
(
Value
v
:
values
)
{
h
=
h
*
31
+
v
.
hashCode
();
}
hash
=
h
;
return
h
;
}
public
Value
[]
getList
()
{
return
values
;
}
...
...
@@ -91,15 +74,6 @@ public class ValueArray extends Value {
return
componentType
;
}
@Override
public
long
getPrecision
()
{
long
p
=
0
;
for
(
Value
v
:
values
)
{
p
+=
v
.
getPrecision
();
}
return
p
;
}
@Override
public
String
getString
()
{
StringBuilder
builder
=
new
StringBuilder
().
append
(
'['
);
...
...
@@ -181,15 +155,6 @@ public class ValueArray extends Value {
return
builder
.
append
(
']'
).
toString
();
}
@Override
public
int
getDisplaySize
()
{
long
size
=
0
;
for
(
Value
v
:
values
)
{
size
+=
v
.
getDisplaySize
();
}
return
MathUtils
.
convertLongToInt
(
size
);
}
@Override
public
boolean
equals
(
Object
other
)
{
if
(!(
other
instanceof
ValueArray
))
{
...
...
@@ -211,15 +176,6 @@ public class ValueArray extends Value {
return
true
;
}
@Override
public
int
getMemory
()
{
int
memory
=
32
;
for
(
Value
v
:
values
)
{
memory
+=
v
.
getMemory
()
+
Constants
.
MEMORY_POINTER
;
}
return
memory
;
}
@Override
public
Value
convertPrecision
(
long
precision
,
boolean
force
)
{
if
(!
force
)
{
...
...
h2/src/main/org/h2/value/ValueCollectionBase.java
0 → 100644
浏览文件 @
a22f1ea3
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
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
;
/**
* Base class for ARRAY and ROW values.
*/
abstract
class
ValueCollectionBase
extends
Value
{
final
Value
[]
values
;
private
int
hash
;
ValueCollectionBase
(
Value
[]
values
)
{
this
.
values
=
values
;
}
@Override
public
int
hashCode
()
{
if
(
hash
!=
0
)
{
return
hash
;
}
int
h
=
getType
();
for
(
Value
v
:
values
)
{
h
=
h
*
31
+
v
.
hashCode
();
}
hash
=
h
;
return
h
;
}
@Override
public
long
getPrecision
()
{
long
p
=
0
;
for
(
Value
v
:
values
)
{
p
+=
v
.
getPrecision
();
}
return
p
;
}
@Override
public
int
getDisplaySize
()
{
long
size
=
0
;
for
(
Value
v
:
values
)
{
size
+=
v
.
getDisplaySize
();
}
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
v
.
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
;
for
(
Value
v
:
values
)
{
memory
+=
v
.
getMemory
()
+
Constants
.
MEMORY_POINTER
;
}
return
memory
;
}
}
h2/src/main/org/h2/value/ValueNull.java
浏览文件 @
a22f1ea3
...
...
@@ -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/main/org/h2/value/ValueRow.java
浏览文件 @
a22f1ea3
...
...
@@ -10,26 +10,21 @@ import java.sql.SQLException;
import
java.util.Arrays
;
import
org.h2.api.ErrorCode
;
import
org.h2.engine.Constants
;
import
org.h2.engine.SysProperties
;
import
org.h2.message.DbException
;
import
org.h2.util.MathUtils
;
/**
* Row value.
*/
public
class
ValueRow
extends
Value
{
public
class
ValueRow
extends
Value
CollectionBase
{
/**
* Empty row.
*/
private
static
final
Object
EMPTY
=
get
(
new
Value
[
0
]);
private
final
Value
[]
values
;
private
int
hash
;
private
ValueRow
(
Value
[]
list
)
{
this
.
values
=
list
;
super
(
list
)
;
}
/**
...
...
@@ -52,19 +47,6 @@ public class ValueRow extends Value {
return
(
ValueRow
)
EMPTY
;
}
@Override
public
int
hashCode
()
{
if
(
hash
!=
0
)
{
return
hash
;
}
int
h
=
1
;
for
(
Value
v
:
values
)
{
h
=
h
*
31
+
v
.
hashCode
();
}
hash
=
h
;
return
h
;
}
public
Value
[]
getList
()
{
return
values
;
}
...
...
@@ -74,15 +56,6 @@ public class ValueRow extends Value {
return
Value
.
ROW
;
}
@Override
public
long
getPrecision
()
{
long
p
=
0
;
for
(
Value
v
:
values
)
{
p
+=
v
.
getPrecision
();
}
return
p
;
}
@Override
public
String
getString
()
{
StringBuilder
builder
=
new
StringBuilder
(
"ROW ("
);
...
...
@@ -165,15 +138,6 @@ public class ValueRow extends Value {
return
builder
.
append
(
')'
).
toString
();
}
@Override
public
int
getDisplaySize
()
{
long
size
=
0
;
for
(
Value
v
:
values
)
{
size
+=
v
.
getDisplaySize
();
}
return
MathUtils
.
convertLongToInt
(
size
);
}
@Override
public
boolean
equals
(
Object
other
)
{
if
(!(
other
instanceof
ValueRow
))
{
...
...
@@ -195,15 +159,6 @@ public class ValueRow extends Value {
return
true
;
}
@Override
public
int
getMemory
()
{
int
memory
=
32
;
for
(
Value
v
:
values
)
{
memory
+=
v
.
getMemory
()
+
Constants
.
MEMORY_POINTER
;
}
return
memory
;
}
@Override
public
Value
convertPrecision
(
long
precision
,
boolean
force
)
{
if
(!
force
)
{
...
...
h2/src/test/org/h2/test/TestAll.java
浏览文件 @
a22f1ea3
...
...
@@ -74,6 +74,7 @@ import org.h2.test.db.TestSetCollation;
import
org.h2.test.db.TestSpaceReuse
;
import
org.h2.test.db.TestSpatial
;
import
org.h2.test.db.TestSpeed
;
import
org.h2.test.db.TestSubqueryPerformanceOnLazyExecutionMode
;
import
org.h2.test.db.TestSynonymForTable
;
import
org.h2.test.db.TestTableEngines
;
import
org.h2.test.db.TestTempTables
;
...
...
@@ -223,7 +224,6 @@ import org.h2.test.unit.TestSort;
import
org.h2.test.unit.TestStreams
;
import
org.h2.test.unit.TestStringCache
;
import
org.h2.test.unit.TestStringUtils
;
import
org.h2.test.unit.TestSubqueryPerformanceOnLazyExecutionMode
;
import
org.h2.test.unit.TestTimeStampWithTimeZone
;
import
org.h2.test.unit.TestTools
;
import
org.h2.test.unit.TestTraceSystem
;
...
...
h2/src/test/org/h2/test/
unit
/TestSubqueryPerformanceOnLazyExecutionMode.java
→
h2/src/test/org/h2/test/
db
/TestSubqueryPerformanceOnLazyExecutionMode.java
浏览文件 @
a22f1ea3
...
...
@@ -3,7 +3,7 @@
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
test
.
unit
;
package
org
.
h2
.
test
.
db
;
import
org.h2.command.dml.SetTypes
;
import
org.h2.test.TestBase
;
...
...
@@ -33,6 +33,11 @@ public class TestSubqueryPerformanceOnLazyExecutionMode extends TestDb {
TestBase
.
createCaller
().
init
().
test
();
}
@Override
public
boolean
isEnabled
()
{
return
!
config
.
travis
;
}
@Override
public
void
test
()
throws
Exception
{
deleteDb
(
"lazySubq"
);
...
...
h2/src/test/org/h2/test/scripts/datatypes/array.sql
浏览文件 @
a22f1ea3
...
...
@@ -23,3 +23,66 @@ 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
,
2
]
IN
(
SELECT
A
FROM
TEST
);
>>
TRUE
SELECT
ROW
(
ARRAY
[
1
,
2
])
IN
(
SELECT
A
FROM
TEST
);
>>
TRUE
SELECT
ARRAY
[
1
,
NULL
]
IN
(
SELECT
A
FROM
TEST
);
>>
null
SELECT
ROW
(
ARRAY
[
1
,
NULL
])
IN
(
SELECT
A
FROM
TEST
);
>>
null
DROP
TABLE
TEST
;
>
ok
h2/src/test/org/h2/test/scripts/datatypes/row.sql
浏览文件 @
a22f1ea3
...
...
@@ -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
h2/src/test/org/h2/test/scripts/dml/select.sql
浏览文件 @
a22f1ea3
...
...
@@ -244,11 +244,11 @@ CREATE TABLE TEST(A INT, B INT);
INSERT
INTO
TEST
VALUES
(
1
,
1
),
(
1
,
2
),
(
2
,
1
),
(
2
,
2
),
(
2
,
3
);
>
update
count
:
5
SELECT
A
,
COUNT
(
B
)
FROM
TEST
GROUP
BY
A
OFFSET
1
;
SELECT
A
,
COUNT
(
B
)
FROM
TEST
GROUP
BY
A
O
RDER
BY
A
O
FFSET
1
;
>
A
COUNT
(
B
)
>
-
--------
>
2
3
>
rows
:
1
>
rows
(
ordered
)
:
1
DROP
TABLE
TEST
;
>
ok
...
...
@@ -463,3 +463,6 @@ SELECT (3, 4) > ALL (SELECT ID, V FROM TEST);
DROP
TABLE
TEST
;
>
ok
SELECT
1
=
ALL
(
SELECT
*
FROM
VALUES
(
NULL
),
(
1
),
(
2
),
(
NULL
)
ORDER
BY
1
);
>>
FALSE
h2/src/test/org/h2/test/synth/TestNestedJoins.java
浏览文件 @
a22f1ea3
...
...
@@ -386,15 +386,17 @@ public class TestNestedJoins extends TestDb {
rs
=
stat
.
executeQuery
(
"select distinct t1.a, t2.a, t3.a from t1 "
+
"right outer join t3 on t1.b=t3.a "
+
"right outer join t2 on t2.b=t1.a"
);
// expected: 1 1 1; null 2 null
assertTrue
(
rs
.
next
());
assertEquals
(
"1"
,
rs
.
getString
(
1
));
assertEquals
(
"1"
,
rs
.
getString
(
2
));
assertEquals
(
"1"
,
rs
.
getString
(
3
));
// expected:
// null 2 null
// 1 1 1
assertTrue
(
rs
.
next
());
assertEquals
(
null
,
rs
.
getString
(
1
));
assertEquals
(
"2"
,
rs
.
getString
(
2
));
assertEquals
(
null
,
rs
.
getString
(
3
));
assertTrue
(
rs
.
next
());
assertEquals
(
"1"
,
rs
.
getString
(
1
));
assertEquals
(
"1"
,
rs
.
getString
(
2
));
assertEquals
(
"1"
,
rs
.
getString
(
3
));
assertFalse
(
rs
.
next
());
stat
.
execute
(
"drop table t1, t2, t3, t4"
);
...
...
h2/src/test/org/h2/test/synth/TestOuterJoins.java
浏览文件 @
a22f1ea3
...
...
@@ -339,15 +339,17 @@ public class TestOuterJoins extends TestDb {
"ON T2.B = T1.A"
,
sql
);
rs
=
stat
.
executeQuery
(
"select distinct t1.a, t2.a, t3.a from t1 "
+
"right outer join t3 on t1.b=t3.a right outer join t2 on t2.b=t1.a"
);
// expected: 1 1 1; null 2 null
assertTrue
(
rs
.
next
());
assertEquals
(
"1"
,
rs
.
getString
(
1
));
assertEquals
(
"1"
,
rs
.
getString
(
2
));
assertEquals
(
"1"
,
rs
.
getString
(
3
));
// expected:
// null 2 null
// 1 1 1
assertTrue
(
rs
.
next
());
assertEquals
(
null
,
rs
.
getString
(
1
));
assertEquals
(
"2"
,
rs
.
getString
(
2
));
assertEquals
(
null
,
rs
.
getString
(
3
));
assertTrue
(
rs
.
next
());
assertEquals
(
"1"
,
rs
.
getString
(
1
));
assertEquals
(
"1"
,
rs
.
getString
(
2
));
assertEquals
(
"1"
,
rs
.
getString
(
3
));
assertFalse
(
rs
.
next
());
stat
.
execute
(
"drop table t1, t2, t3, t4"
);
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论