Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
e863d560
Unverified
提交
e863d560
authored
2月 07, 2018
作者:
Noel Grandin
提交者:
GitHub
2月 07, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #850 from katzyn/any
Add support for = ANY(?)
上级
50f0343e
4e3af4c7
显示空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
261 行增加
和
48 行删除
+261
-48
performance.html
h2/src/docsrc/html/performance.html
+1
-1
Parser.java
h2/src/main/org/h2/command/Parser.java
+57
-47
ConditionInParameter.java
h2/src/main/org/h2/expression/ConditionInParameter.java
+164
-0
JdbcDataSource.java
h2/src/main/org/h2/jdbcx/JdbcDataSource.java
+2
-0
TestPreparedStatement.java
h2/src/test/org/h2/test/jdbc/TestPreparedStatement.java
+37
-0
没有找到文件。
h2/src/docsrc/html/performance.html
浏览文件 @
e863d560
...
@@ -490,7 +490,7 @@ Instead, use a prepared statement with arrays as in the following example:
...
@@ -490,7 +490,7 @@ Instead, use a prepared statement with arrays as in the following example:
</p>
</p>
<pre>
<pre>
PreparedStatement prep = conn.prepareStatement(
PreparedStatement prep = conn.prepareStatement(
"SELECT *
FROM TABLE(X INT=?) T INNER JOIN TEST ON T.X=TEST.ID
");
"SELECT *
TEST.ID = ANY(?)
");
prep.setObject(1, new Object[] { "1", "2" });
prep.setObject(1, new Object[] { "1", "2" });
ResultSet rs = prep.executeQuery();
ResultSet rs = prep.executeQuery();
</pre>
</pre>
...
...
h2/src/main/org/h2/command/Parser.java
浏览文件 @
e863d560
...
@@ -112,6 +112,7 @@ import org.h2.expression.Comparison;
...
@@ -112,6 +112,7 @@ import org.h2.expression.Comparison;
import
org.h2.expression.ConditionAndOr
;
import
org.h2.expression.ConditionAndOr
;
import
org.h2.expression.ConditionExists
;
import
org.h2.expression.ConditionExists
;
import
org.h2.expression.ConditionIn
;
import
org.h2.expression.ConditionIn
;
import
org.h2.expression.ConditionInParameter
;
import
org.h2.expression.ConditionInSelect
;
import
org.h2.expression.ConditionInSelect
;
import
org.h2.expression.ConditionNot
;
import
org.h2.expression.ConditionNot
;
import
org.h2.expression.Expression
;
import
org.h2.expression.Expression
;
...
@@ -2504,9 +2505,14 @@ public class Parser {
...
@@ -2504,9 +2505,14 @@ public class Parser {
read
(
")"
);
read
(
")"
);
}
else
if
(
readIf
(
"ANY"
)
||
readIf
(
"SOME"
))
{
}
else
if
(
readIf
(
"ANY"
)
||
readIf
(
"SOME"
))
{
read
(
"("
);
read
(
"("
);
if
(
currentTokenType
==
PARAMETER
&&
compareType
==
0
)
{
Parameter
p
=
readParameter
();
r
=
new
ConditionInParameter
(
database
,
r
,
p
);
}
else
{
Query
query
=
parseSelect
();
Query
query
=
parseSelect
();
r
=
new
ConditionInSelect
(
database
,
r
,
query
,
false
,
r
=
new
ConditionInSelect
(
database
,
r
,
query
,
false
,
compareType
);
compareType
);
}
read
(
")"
);
read
(
")"
);
}
else
{
}
else
{
Expression
right
=
readConcat
();
Expression
right
=
readConcat
();
...
@@ -3001,21 +3007,7 @@ public class Parser {
...
@@ -3001,21 +3007,7 @@ public class Parser {
return
new
ExpressionColumn
(
database
,
null
,
objectName
,
name
);
return
new
ExpressionColumn
(
database
,
null
,
objectName
,
name
);
}
}
private
Expression
readTerm
()
{
private
Parameter
readParameter
()
{
Expression
r
;
switch
(
currentTokenType
)
{
case
AT:
read
();
r
=
new
Variable
(
session
,
readAliasIdentifier
());
if
(
readIf
(
":="
))
{
Expression
value
=
readExpression
();
Function
function
=
Function
.
getFunction
(
database
,
"SET"
);
function
.
setParameter
(
0
,
r
);
function
.
setParameter
(
1
,
value
);
r
=
function
;
}
break
;
case
PARAMETER:
// there must be no space between ? and the number
// there must be no space between ? and the number
boolean
indexed
=
Character
.
isDigit
(
sqlCommandChars
[
parseIndex
]);
boolean
indexed
=
Character
.
isDigit
(
sqlCommandChars
[
parseIndex
]);
...
@@ -3059,7 +3051,25 @@ public class Parser {
...
@@ -3059,7 +3051,25 @@ public class Parser {
p
=
new
Parameter
(
parameters
.
size
());
p
=
new
Parameter
(
parameters
.
size
());
}
}
parameters
.
add
(
p
);
parameters
.
add
(
p
);
r
=
p
;
return
p
;
}
private
Expression
readTerm
()
{
Expression
r
;
switch
(
currentTokenType
)
{
case
AT:
read
();
r
=
new
Variable
(
session
,
readAliasIdentifier
());
if
(
readIf
(
":="
))
{
Expression
value
=
readExpression
();
Function
function
=
Function
.
getFunction
(
database
,
"SET"
);
function
.
setParameter
(
0
,
r
);
function
.
setParameter
(
1
,
value
);
r
=
function
;
}
break
;
case
PARAMETER:
r
=
readParameter
();
break
;
break
;
case
KEYWORD:
case
KEYWORD:
if
(
isToken
(
"SELECT"
)
||
isToken
(
"FROM"
)
||
isToken
(
"WITH"
))
{
if
(
isToken
(
"SELECT"
)
||
isToken
(
"FROM"
)
||
isToken
(
"WITH"
))
{
...
...
h2/src/main/org/h2/expression/ConditionInParameter.java
0 → 100644
浏览文件 @
e863d560
/*
* 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
.
expression
;
import
java.util.AbstractList
;
import
org.h2.engine.Database
;
import
org.h2.engine.Session
;
import
org.h2.index.IndexCondition
;
import
org.h2.table.ColumnResolver
;
import
org.h2.table.TableFilter
;
import
org.h2.value.Value
;
import
org.h2.value.ValueArray
;
import
org.h2.value.ValueBoolean
;
import
org.h2.value.ValueNull
;
/**
* A condition with parameter as {@code = ANY(?)}.
*/
public
class
ConditionInParameter
extends
Condition
{
private
static
final
class
ParameterList
extends
AbstractList
<
Expression
>
{
private
final
Parameter
parameter
;
ParameterList
(
Parameter
parameter
)
{
this
.
parameter
=
parameter
;
}
@Override
public
Expression
get
(
int
index
)
{
Value
value
=
parameter
.
getParamValue
();
if
(
value
instanceof
ValueArray
)
{
return
ValueExpression
.
get
(((
ValueArray
)
value
).
getList
()[
index
]);
}
if
(
index
!=
0
)
{
throw
new
IndexOutOfBoundsException
();
}
return
ValueExpression
.
get
(
value
);
}
@Override
public
int
size
()
{
if
(!
parameter
.
isValueSet
())
{
return
0
;
}
Value
value
=
parameter
.
getParamValue
();
if
(
value
instanceof
ValueArray
)
{
return
((
ValueArray
)
value
).
getList
().
length
;
}
return
1
;
}
}
private
final
Database
database
;
private
Expression
left
;
final
Parameter
parameter
;
/**
* Create a new {@code = ANY(?)} condition.
*
* @param database
* the database
* @param left
* the expression before {@code = ANY(?)}
* @param parameter
* parameter
*/
public
ConditionInParameter
(
Database
database
,
Expression
left
,
Parameter
parameter
)
{
this
.
database
=
database
;
this
.
left
=
left
;
this
.
parameter
=
parameter
;
}
@Override
public
Value
getValue
(
Session
session
)
{
Value
l
=
left
.
getValue
(
session
);
if
(
l
==
ValueNull
.
INSTANCE
)
{
return
l
;
}
boolean
result
=
false
;
boolean
hasNull
=
false
;
Value
value
=
parameter
.
getValue
(
session
);
if
(
value
instanceof
ValueArray
)
{
for
(
Value
r
:
((
ValueArray
)
value
).
getList
())
{
if
(
r
==
ValueNull
.
INSTANCE
)
{
hasNull
=
true
;
}
else
{
r
=
r
.
convertTo
(
l
.
getType
());
result
=
Comparison
.
compareNotNull
(
database
,
l
,
r
,
Comparison
.
EQUAL
);
if
(
result
)
{
break
;
}
}
}
}
else
{
if
(
value
==
ValueNull
.
INSTANCE
)
{
hasNull
=
true
;
}
else
{
value
=
value
.
convertTo
(
l
.
getType
());
result
=
Comparison
.
compareNotNull
(
database
,
l
,
value
,
Comparison
.
EQUAL
);
}
}
if
(!
result
&&
hasNull
)
{
return
ValueNull
.
INSTANCE
;
}
return
ValueBoolean
.
get
(
result
);
}
@Override
public
void
mapColumns
(
ColumnResolver
resolver
,
int
level
)
{
left
.
mapColumns
(
resolver
,
level
);
}
@Override
public
Expression
optimize
(
Session
session
)
{
left
=
left
.
optimize
(
session
);
if
(
left
.
isConstant
()
&&
left
==
ValueExpression
.
getNull
())
{
return
left
;
}
return
this
;
}
@Override
public
void
createIndexConditions
(
Session
session
,
TableFilter
filter
)
{
if
(!(
left
instanceof
ExpressionColumn
))
{
return
;
}
ExpressionColumn
l
=
(
ExpressionColumn
)
left
;
if
(
filter
!=
l
.
getTableFilter
())
{
return
;
}
filter
.
addIndexCondition
(
IndexCondition
.
getInList
(
l
,
new
ParameterList
(
parameter
)));
}
@Override
public
void
setEvaluatable
(
TableFilter
tableFilter
,
boolean
b
)
{
left
.
setEvaluatable
(
tableFilter
,
b
);
}
@Override
public
String
getSQL
()
{
return
'('
+
left
.
getSQL
()
+
" = ANY("
+
parameter
.
getSQL
()
+
"))"
;
}
@Override
public
void
updateAggregate
(
Session
session
)
{
left
.
updateAggregate
(
session
);
}
@Override
public
boolean
isEverything
(
ExpressionVisitor
visitor
)
{
return
left
.
isEverything
(
visitor
)
&&
parameter
.
isEverything
(
visitor
);
}
@Override
public
int
getCost
()
{
return
left
.
getCost
();
}
}
h2/src/main/org/h2/jdbcx/JdbcDataSource.java
浏览文件 @
e863d560
...
@@ -405,6 +405,7 @@ public class JdbcDataSource extends TraceObject implements XADataSource,
...
@@ -405,6 +405,7 @@ public class JdbcDataSource extends TraceObject implements XADataSource,
* Return an object of this class if possible.
* Return an object of this class if possible.
*
*
* @param iface the class
* @param iface the class
* @return this
*/
*/
@Override
@Override
@SuppressWarnings
(
"unchecked"
)
@SuppressWarnings
(
"unchecked"
)
...
@@ -423,6 +424,7 @@ public class JdbcDataSource extends TraceObject implements XADataSource,
...
@@ -423,6 +424,7 @@ public class JdbcDataSource extends TraceObject implements XADataSource,
* Checks if unwrap can return an object of this class.
* Checks if unwrap can return an object of this class.
*
*
* @param iface the class
* @param iface the class
* @return whether or not the interface is assignable from this class
*/
*/
@Override
@Override
public
boolean
isWrapperFor
(
Class
<?>
iface
)
throws
SQLException
{
public
boolean
isWrapperFor
(
Class
<?>
iface
)
throws
SQLException
{
...
...
h2/src/test/org/h2/test/jdbc/TestPreparedStatement.java
浏览文件 @
e863d560
...
@@ -102,6 +102,7 @@ public class TestPreparedStatement extends TestBase {
...
@@ -102,6 +102,7 @@ public class TestPreparedStatement extends TestBase {
conn
.
close
();
conn
.
close
();
testPreparedStatementWithLiteralsNone
();
testPreparedStatementWithLiteralsNone
();
testPreparedStatementWithIndexedParameterAndLiteralsNone
();
testPreparedStatementWithIndexedParameterAndLiteralsNone
();
testPreparedStatementWithAnyParameter
();
deleteDb
(
"preparedStatement"
);
deleteDb
(
"preparedStatement"
);
}
}
...
@@ -1548,7 +1549,43 @@ public class TestPreparedStatement extends TestBase {
...
@@ -1548,7 +1549,43 @@ public class TestPreparedStatement extends TestBase {
deleteDb
(
"preparedStatement"
);
deleteDb
(
"preparedStatement"
);
}
}
private
void
testPreparedStatementWithAnyParameter
()
throws
SQLException
{
deleteDb
(
"preparedStatement"
);
Connection
conn
=
getConnection
(
"preparedStatement"
);
conn
.
prepareStatement
(
"CREATE TABLE TEST(ID INT PRIMARY KEY, VALUE INT UNIQUE)"
).
execute
();
PreparedStatement
ps
=
conn
.
prepareStatement
(
"INSERT INTO TEST(ID, VALUE) VALUES (?, ?)"
);
for
(
int
i
=
0
;
i
<
10_000
;
i
++)
{
ps
.
setInt
(
1
,
i
);
ps
.
setInt
(
2
,
i
*
10
);
ps
.
executeUpdate
();
}
Object
[]
values
=
{-
100
,
10
,
200
,
3_000
,
40_000
,
500_000
};
int
[]
expected
=
{
1
,
20
,
300
,
4_000
};
// Ensure that other methods return the same results
ps
=
conn
.
prepareStatement
(
"SELECT ID FROM TEST WHERE VALUE IN (SELECT * FROM TABLE(X INT=?)) ORDER BY ID"
);
anyParameterCheck
(
ps
,
values
,
expected
);
ps
=
conn
.
prepareStatement
(
"SELECT ID FROM TEST INNER JOIN TABLE(X INT=?) T ON TEST.VALUE = T.X"
);
anyParameterCheck
(
ps
,
values
,
expected
);
// Test expression = ANY(?)
ps
=
conn
.
prepareStatement
(
"SELECT ID FROM TEST WHERE VALUE = ANY(?)"
);
assertThrows
(
ErrorCode
.
PARAMETER_NOT_SET_1
,
ps
).
executeQuery
();
anyParameterCheck
(
ps
,
values
,
expected
);
anyParameterCheck
(
ps
,
300
,
new
int
[]
{
30
});
anyParameterCheck
(
ps
,
-
5
,
new
int
[
0
]);
conn
.
close
();
deleteDb
(
"preparedStatement"
);
}
private
void
anyParameterCheck
(
PreparedStatement
ps
,
Object
values
,
int
[]
expected
)
throws
SQLException
{
ps
.
setObject
(
1
,
values
);
try
(
ResultSet
rs
=
ps
.
executeQuery
())
{
for
(
int
exp
:
expected
)
{
assertTrue
(
rs
.
next
());
assertEquals
(
exp
,
rs
.
getInt
(
1
));
}
assertFalse
(
rs
.
next
());
}
}
private
void
checkBigDecimal
(
ResultSet
rs
,
String
[]
value
)
throws
SQLException
{
private
void
checkBigDecimal
(
ResultSet
rs
,
String
[]
value
)
throws
SQLException
{
for
(
String
v
:
value
)
{
for
(
String
v
:
value
)
{
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论