Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
47ff9145
Unverified
提交
47ff9145
authored
5月 27, 2018
作者:
Evgenij Ryazanov
提交者:
GitHub
5月 27, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #1164 from katzyn/parser
More fixes for parsing of MERGE USING and other changes in Parser
上级
3c10d9c9
505759e4
隐藏空白字符变更
内嵌
并排
正在显示
8 个修改的文件
包含
157 行增加
和
114 行删除
+157
-114
help.csv
h2/src/docsrc/help/help.csv
+41
-13
Command.java
h2/src/main/org/h2/command/Command.java
+2
-2
CommandContainer.java
h2/src/main/org/h2/command/CommandContainer.java
+3
-2
CommandList.java
h2/src/main/org/h2/command/CommandList.java
+4
-2
Parser.java
h2/src/main/org/h2/command/Parser.java
+80
-84
MergeUsing.java
h2/src/main/org/h2/command/dml/MergeUsing.java
+0
-10
TestMergeUsing.java
h2/src/test/org/h2/test/db/TestMergeUsing.java
+1
-1
mergeUsing.sql
h2/src/test/org/h2/test/scripts/dml/mergeUsing.sql
+26
-0
没有找到文件。
h2/src/docsrc/help/help.csv
浏览文件 @
47ff9145
...
...
@@ -45,11 +45,7 @@ SELECT * FROM (SELECT ID, COUNT(*) FROM TEST
"
"Commands (DML)","INSERT","
INSERT INTO tableName
{ [ ( columnName [,...] ) ]
{ VALUES { ( { DEFAULT | expression } [,...] ) } [,...]
| [ DIRECT ] [ SORTED ] select } } |
{ SET { columnName = { DEFAULT | expression } } [,...] }
INSERT INTO tableName insertColumnsAndSource
","
Inserts a new row / new rows into a table.
...
...
@@ -61,9 +57,7 @@ INSERT INTO TEST VALUES(1, 'Hello')
"
"Commands (DML)","UPDATE","
UPDATE tableName [ [ AS ] newTableAlias ] SET
{ { columnName = { DEFAULT | expression } } [,...] } |
{ ( columnName [,...] ) = ( select ) }
UPDATE tableName [ [ AS ] newTableAlias ] SET setClauseList
[ WHERE expression ] [ ORDER BY order [,...] ] [ LIMIT expression ]
","
Updates data in a table.
...
...
@@ -74,7 +68,7 @@ UPDATE PERSON P SET NAME=(SELECT A.NAME FROM ADDRESS A WHERE A.ID=P.ID);
"
"Commands (DML)","DELETE","
DELETE [ TOP term ] FROM tableName
[ WHERE expression ] [ LIMIT term ]
DELETE [ TOP term ] FROM tableName
deleteSearchCondition
","
Deletes rows form a table.
If TOP or LIMIT is specified, at most the specified number of rows are deleted (no limit if null or smaller than zero).
...
...
@@ -129,16 +123,19 @@ MERGE INTO TEST KEY(ID) VALUES(2, 'World')
MERGE INTO targetTableName [ [AS] targetAlias]
USING { ( select ) | sourceTableName }[ [AS] sourceAlias ]
ON ( expression )
[ WHEN MATCHED THEN [ update ] [ delete] ]
[ WHEN NOT MATCHED THEN insert ]
[ WHEN MATCHED THEN
[ UPDATE SET setClauseList ] [ DELETE deleteSearchCondition ] ]
[ WHEN NOT MATCHED THEN INSERT insertColumnsAndSource ]
","
Updates or deletes existing rows, and insert rows that don't exist. The ON clause
specifies the matching column expression and must be specified. If more than one row
is updated per input row, an exception is thrown.
If the source data contains duplicate rows (specifically those columns used in the
row matching ON clause), then an exception is thrown to prevent two updates applying
to the same target row. The embedded update, delete or insert statements can not re-specify
the target table name.
to the same target row.
WHEN MATCHED THEN or WHEN NOT MATCHED THEN clauses or both of them in any order should be specified.
If WHEN MATCHED THEN is specified it should contain UPDATE or DELETE clauses of both of them.
If statement doesn't need a source table a DUAL table can be substituted.
","
MERGE INTO TARGET_TABLE AS T USING SOURCE_TABLE AS S
ON (T.ID = S.ID)
...
...
@@ -154,6 +151,9 @@ MERGE INTO TARGET_TABLE AS T USING (SELECT * FROM SOURCE_TABLE) AS S
DELETE WHERE T.COL2='FINAL'
WHEN NOT MATCHED THEN
INSERT (ID,COL1,COL2) VALUES(S.ID,S.COL1,S.COL2)
MERGE INTO TARGET_TABLE USING DUAL ON (ID = 1)
WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (1, 'Test')
WHEN MATCHED THEN UPDATE SET NAME = 'Test'
"
"Commands (DML)","RUNSCRIPT","
...
...
@@ -2252,6 +2252,14 @@ SELECT CAST(0 AS DOUBLE)
SELECT -1.4e-10
"
"Other Grammar","Delete search condition","
[ WHERE expression ] [ LIMIT term ]
","
Search condition for DELETE statement.
","
WHERE ID = 2
"
"Other Grammar","Digit","
0-9
","
...
...
@@ -2313,6 +2321,17 @@ the column in the same way.
NAME
"
"Other Grammar","Insert columns and source","
{ [ ( columnName [,...] ) ]
{ VALUES { ( { DEFAULT | expression } [,...] ) } [,...]
| [ DIRECT ] [ SORTED ] select } } |
{ SET { columnName = { DEFAULT | expression } } [,...] }
","
Names of columns and their values for INSERT statement.
","
(ID, NAME) VALUES (1, 'Test')
"
"Other Grammar","Int","
[ + | - ] number
","
...
...
@@ -2438,6 +2457,15 @@ An expression in a SELECT statement.
ID AS VALUE
"
"Other Grammar","Set clause list","
{ { columnName = { DEFAULT | expression } } [,...] } |
{ ( columnName [,...] ) = ( select ) }
","
List of SET clauses.
","
NAME = 'Test', VALUE = 2
"
"Other Grammar","String","
'anythingExceptSingleQuote'
","
...
...
h2/src/main/org/h2/command/Command.java
浏览文件 @
47ff9145
...
...
@@ -46,8 +46,8 @@ public abstract class Command implements CommandInterface {
private
boolean
canReuse
;
Command
(
Parser
parser
,
String
sql
)
{
this
.
session
=
parser
.
getSession
()
;
Command
(
Session
session
,
String
sql
)
{
this
.
session
=
session
;
this
.
sql
=
sql
;
trace
=
session
.
getDatabase
().
getTrace
(
Trace
.
COMMAND
);
}
...
...
h2/src/main/org/h2/command/CommandContainer.java
浏览文件 @
47ff9145
...
...
@@ -9,6 +9,7 @@ import java.util.ArrayList;
import
org.h2.api.DatabaseEventListener
;
import
org.h2.command.dml.Explain
;
import
org.h2.command.dml.Query
;
import
org.h2.engine.Session
;
import
org.h2.expression.Parameter
;
import
org.h2.expression.ParameterInterface
;
import
org.h2.result.ResultInterface
;
...
...
@@ -26,8 +27,8 @@ public class CommandContainer extends Command {
private
boolean
readOnlyKnown
;
private
boolean
readOnly
;
CommandContainer
(
Parser
parser
,
String
sql
,
Prepared
prepared
)
{
super
(
parser
,
sql
);
CommandContainer
(
Session
session
,
String
sql
,
Prepared
prepared
)
{
super
(
session
,
sql
);
prepared
.
setCommand
(
this
);
this
.
prepared
=
prepared
;
}
...
...
h2/src/main/org/h2/command/CommandList.java
浏览文件 @
47ff9145
...
...
@@ -6,6 +6,8 @@
package
org
.
h2
.
command
;
import
java.util.ArrayList
;
import
org.h2.engine.Session
;
import
org.h2.expression.ParameterInterface
;
import
org.h2.result.ResultInterface
;
...
...
@@ -17,8 +19,8 @@ class CommandList extends Command {
private
final
Command
command
;
private
final
String
remaining
;
CommandList
(
Parser
parser
,
String
sql
,
Command
c
,
String
remaining
)
{
super
(
parser
,
sql
);
CommandList
(
Session
session
,
String
sql
,
Command
c
,
String
remaining
)
{
super
(
session
,
sql
);
this
.
command
=
c
;
this
.
remaining
=
remaining
;
}
...
...
h2/src/main/org/h2/command/Parser.java
浏览文件 @
47ff9145
...
...
@@ -8,6 +8,13 @@
*/
package
org
.
h2
.
command
;
import
static
org
.
h2
.
util
.
ParserUtil
.
FALSE
;
import
static
org
.
h2
.
util
.
ParserUtil
.
IDENTIFIER
;
import
static
org
.
h2
.
util
.
ParserUtil
.
KEYWORD
;
import
static
org
.
h2
.
util
.
ParserUtil
.
NULL
;
import
static
org
.
h2
.
util
.
ParserUtil
.
ROWNUM
;
import
static
org
.
h2
.
util
.
ParserUtil
.
TRUE
;
import
java.math.BigDecimal
;
import
java.math.BigInteger
;
import
java.nio.charset.Charset
;
...
...
@@ -189,13 +196,7 @@ public class Parser {
private
static
final
int
CHAR_STRING
=
7
,
CHAR_DOT
=
8
,
CHAR_DOLLAR_QUOTED_STRING
=
9
;
// this are token types
private
static
final
int
KEYWORD
=
ParserUtil
.
KEYWORD
;
private
static
final
int
IDENTIFIER
=
ParserUtil
.
IDENTIFIER
;
private
static
final
int
NULL
=
ParserUtil
.
NULL
;
private
static
final
int
TRUE
=
ParserUtil
.
TRUE
;
private
static
final
int
FALSE
=
ParserUtil
.
FALSE
;
private
static
final
int
ROWNUM
=
ParserUtil
.
ROWNUM
;
// this are token types, see also types in ParserUtil
private
static
final
int
PARAMETER
=
10
,
END
=
11
,
VALUE
=
12
;
private
static
final
int
EQUAL
=
13
,
BIGGER_EQUAL
=
14
,
BIGGER
=
15
;
private
static
final
int
SMALLER
=
16
,
SMALLER_EQUAL
=
17
,
NOT_EQUAL
=
18
;
...
...
@@ -285,11 +286,11 @@ public class Parser {
throw
getSyntaxError
();
}
p
.
prepare
();
Command
c
=
new
CommandContainer
(
this
,
sql
,
p
);
Command
c
=
new
CommandContainer
(
session
,
sql
,
p
);
if
(
hasMore
)
{
String
remaining
=
originalSQL
.
substring
(
parseIndex
);
if
(!
StringUtils
.
isWhitespaceOrEmpty
(
remaining
))
{
c
=
new
CommandList
(
this
,
sql
,
c
,
remaining
);
c
=
new
CommandList
(
session
,
sql
,
c
,
remaining
);
}
}
return
c
;
...
...
@@ -574,7 +575,7 @@ public class Parser {
command
.
setTable
(
table
);
}
if
(
readIf
(
"SAMPLE_SIZE"
))
{
command
.
setTop
(
read
Posi
tiveInt
());
command
.
setTop
(
read
NonNega
tiveInt
());
}
return
command
;
}
...
...
@@ -734,10 +735,9 @@ public class Parser {
}
private
Column
readTableColumn
(
TableFilter
filter
)
{
String
tableAlias
=
null
;
String
columnName
=
readColumnIdentifier
();
if
(
readIf
(
"."
))
{
tableAlias
=
columnName
;
String
tableAlias
=
columnName
;
columnName
=
readColumnIdentifier
();
if
(
readIf
(
"."
))
{
String
schema
=
tableAlias
;
...
...
@@ -1156,11 +1156,15 @@ public class Parser {
TableFilter
sourceTableFilter
=
readSimpleTableFilter
(
0
,
excludeIdentifiers
);
command
.
setSourceTableFilter
(
sourceTableFilter
);
StringBuilder
buff
=
new
StringBuilder
(
"SELECT * FROM "
);
appendTableWithSchemaAndAlias
(
buff
,
sourceTableFilter
.
getTable
(),
sourceTableFilter
.
getTableAlias
());
Prepared
preparedQuery
=
prepare
(
session
,
buff
.
toString
(),
null
/*paramValues*/
);
command
.
setQuery
((
Select
)
preparedQuery
);
Select
preparedQuery
=
new
Select
(
session
);
ArrayList
<
Expression
>
expr
=
new
ArrayList
<>(
1
);
expr
.
add
(
new
Wildcard
(
null
,
null
));
preparedQuery
.
setExpressions
(
expr
);
TableFilter
filter
=
new
TableFilter
(
session
,
sourceTableFilter
.
getTable
(),
sourceTableFilter
.
getTableAlias
(),
rightsChecked
,
preparedQuery
,
0
,
null
);
preparedQuery
.
addTableFilter
(
filter
,
true
);
preparedQuery
.
init
();
command
.
setQuery
(
preparedQuery
);
}
read
(
"ON"
);
read
(
"("
);
...
...
@@ -1168,9 +1172,20 @@ public class Parser {
command
.
setOnCondition
(
condition
);
read
(
")"
);
boolean
matched
=
parseWhenMatched
(
command
);
if
(
parseWhenNotMatched
(
command
)
&&
!
matched
)
{
read
(
"WHEN"
);
boolean
matched
=
readIf
(
"MATCHED"
);
if
(
matched
)
{
parseWhenMatched
(
command
);
}
else
{
parseWhenNotMatched
(
command
);
}
if
(
readIf
(
"WHEN"
))
{
if
(
matched
)
{
parseWhenNotMatched
(
command
);
}
else
{
read
(
"MATCHED"
);
parseWhenMatched
(
command
);
}
}
setSQL
(
command
,
"MERGE"
,
start
);
...
...
@@ -1188,17 +1203,17 @@ public class Parser {
return
command
;
}
private
boolean
parseWhenMatched
(
MergeUsing
command
)
{
if
(!
readIfAll
(
"WHEN"
,
"MATCHED"
,
"THEN"
))
{
return
false
;
}
private
void
parseWhenMatched
(
MergeUsing
command
)
{
read
(
"THEN"
);
int
startMatched
=
lastParseIndex
;
boolean
ok
=
false
;
if
(
readIf
(
"UPDATE"
))
{
Update
updateCommand
=
new
Update
(
session
);
TableFilter
filter
=
command
.
getTargetTableFilter
();
updateCommand
.
setTableFilter
(
filter
);
parseUpdateSetClause
(
updateCommand
,
filter
,
startMatched
);
command
.
setUpdateCommand
(
updateCommand
);
ok
=
true
;
}
startMatched
=
lastParseIndex
;
if
(
readIf
(
"DELETE"
))
{
...
...
@@ -1207,21 +1222,25 @@ public class Parser {
deleteCommand
.
setTableFilter
(
filter
);
parseDeleteGivenTable
(
deleteCommand
,
null
,
startMatched
);
command
.
setDeleteCommand
(
deleteCommand
);
ok
=
true
;
}
if
(!
ok
)
{
throw
getSyntaxError
();
}
return
true
;
}
private
boolean
parseWhenNotMatched
(
MergeUsing
command
)
{
if
(!
readIfAll
(
"WHEN"
,
"NOT"
,
"MATCHED"
,
"THEN"
))
{
return
false
;
}
private
void
parseWhenNotMatched
(
MergeUsing
command
)
{
read
(
"NOT"
);
read
(
"MATCHED"
)
;
read
(
"THEN"
);
if
(
readIf
(
"INSERT"
))
{
Insert
insertCommand
=
new
Insert
(
session
);
insertCommand
.
setTable
(
command
.
getTargetTable
());
parseInsertGivenTable
(
insertCommand
,
command
.
getTargetTable
());
command
.
setInsertCommand
(
insertCommand
);
}
else
{
throw
getSyntaxError
();
}
return
true
;
}
private
static
void
appendTableWithSchemaAndAlias
(
StringBuilder
buff
,
Table
table
,
String
alias
)
{
...
...
@@ -1964,9 +1983,8 @@ public class Parser {
}
private
Query
parseSelect
()
{
Query
command
=
null
;
int
paramIndex
=
parameters
.
size
();
command
=
parseSelectUnion
();
Query
command
=
parseSelectUnion
();
int
size
=
parameters
.
size
();
ArrayList
<
Parameter
>
params
=
new
ArrayList
<>(
size
);
for
(
int
i
=
paramIndex
;
i
<
size
;
i
++)
{
...
...
@@ -2042,10 +2060,7 @@ public class Parser {
}
ArrayList
<
SelectOrderBy
>
orderList
=
Utils
.
newSmallArrayList
();
do
{
boolean
canBeNumber
=
true
;
if
(
readIf
(
"="
))
{
canBeNumber
=
false
;
}
boolean
canBeNumber
=
!
readIf
(
"="
);
SelectOrderBy
order
=
new
SelectOrderBy
();
Expression
expr
=
readExpression
();
if
(
canBeNumber
&&
expr
instanceof
ValueExpression
&&
...
...
@@ -2159,7 +2174,7 @@ public class Parser {
return
command
;
}
if
(
readIf
(
"WITH"
))
{
Query
query
=
null
;
Query
query
;
try
{
query
=
(
Query
)
parseWith
();
}
catch
(
ClassCastException
e
)
{
...
...
@@ -2691,7 +2706,7 @@ public class Parser {
}
private
JavaFunction
readJavaFunction
(
Schema
schema
,
String
functionName
,
boolean
throwIfNotFound
)
{
FunctionAlias
functionAlias
=
null
;
FunctionAlias
functionAlias
;
if
(
schema
!=
null
)
{
functionAlias
=
schema
.
findFunction
(
functionName
);
}
else
{
...
...
@@ -3403,10 +3418,10 @@ public class Parser {
return
function
;
}
private
int
read
Posi
tiveInt
()
{
private
int
read
NonNega
tiveInt
()
{
int
v
=
readInt
();
if
(
v
<
0
)
{
throw
DbException
.
getInvalidValueException
(
"
posi
tive integer"
,
v
);
throw
DbException
.
getInvalidValueException
(
"
non-nega
tive integer"
,
v
);
}
return
v
;
}
...
...
@@ -3452,14 +3467,21 @@ public class Parser {
}
private
boolean
readBooleanSetting
()
{
if
(
currentTokenType
==
VALUE
)
{
switch
(
currentTokenType
)
{
case
TRUE:
read
();
return
true
;
case
FALSE:
read
();
return
false
;
case
VALUE:
boolean
result
=
currentValue
.
getBoolean
();
read
();
return
result
;
}
if
(
readIf
(
"
TRUE"
)
||
readIf
(
"
ON"
))
{
if
(
readIf
(
"ON"
))
{
return
true
;
}
else
if
(
readIf
(
"
FALSE"
)
||
readIf
(
"
OFF"
))
{
}
else
if
(
readIf
(
"OFF"
))
{
return
false
;
}
else
{
throw
getSyntaxError
();
...
...
@@ -3547,26 +3569,6 @@ public class Parser {
return
false
;
}
/*
* Reads every token in list, in order - returns true if all are found.
* If any are not found, returns false - AND resets parsing back to state when called.
*/
private
boolean
readIfAll
(
String
...
tokens
)
{
// save parse location in case we have to fail this test
int
start
=
lastParseIndex
;
for
(
String
token:
tokens
)
{
if
(!
currentTokenQuoted
&&
equalsToken
(
token
,
currentToken
))
{
read
();
}
else
{
// read failed - revert parse location to before when called
parseIndex
=
start
;
read
();
return
false
;
}
}
return
true
;
}
private
boolean
isToken
(
String
token
)
{
boolean
result
=
equalsToken
(
token
,
currentToken
)
&&
!
currentTokenQuoted
;
...
...
@@ -3753,12 +3755,11 @@ public class Parser {
return
;
}
case
CHAR_DOLLAR_QUOTED_STRING:
{
String
result
=
null
;
int
begin
=
i
-
1
;
while
(
types
[
i
]
==
CHAR_DOLLAR_QUOTED_STRING
)
{
i
++;
}
result
=
sqlCommand
.
substring
(
begin
,
i
);
String
result
=
sqlCommand
.
substring
(
begin
,
i
);
currentToken
=
"'"
;
checkLiterals
(
true
);
currentValue
=
ValueString
.
get
(
StringUtils
.
cache
(
result
),
...
...
@@ -3877,10 +3878,6 @@ public class Parser {
currentTokenType
=
VALUE
;
}
public
Session
getSession
()
{
return
session
;
}
private
void
initialize
(
String
sql
)
{
if
(
sql
==
null
)
{
sql
=
""
;
...
...
@@ -4306,7 +4303,7 @@ public class Parser {
column
.
setSequence
(
sequence
);
}
if
(
readIf
(
"SELECTIVITY"
))
{
int
value
=
read
Posi
tiveInt
();
int
value
=
read
NonNega
tiveInt
();
column
.
setSelectivity
(
value
);
}
String
comment
=
readCommentIf
();
...
...
@@ -4354,7 +4351,7 @@ public class Parser {
}
}
else
if
(
readIf
(
"TIME"
))
{
if
(
readIf
(
"("
))
{
originalScale
=
read
Posi
tiveInt
();
originalScale
=
read
NonNega
tiveInt
();
if
(
originalScale
>
ValueTime
.
MAXIMUM_SCALE
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_VALUE_SCALE_PRECISION
,
Integer
.
toString
(
originalScale
));
}
...
...
@@ -4367,10 +4364,10 @@ public class Parser {
}
}
else
if
(
readIf
(
"TIMESTAMP"
))
{
if
(
readIf
(
"("
))
{
originalScale
=
read
Posi
tiveInt
();
originalScale
=
read
NonNega
tiveInt
();
// Allow non-standard TIMESTAMP(..., ...) syntax
if
(
readIf
(
","
))
{
originalScale
=
read
Posi
tiveInt
();
originalScale
=
read
NonNega
tiveInt
();
}
if
(
originalScale
>
ValueTimestamp
.
MAXIMUM_SCALE
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_VALUE_SCALE_PRECISION
,
Integer
.
toString
(
originalScale
));
...
...
@@ -4458,7 +4455,7 @@ public class Parser {
}
}
else
if
(
original
.
equals
(
"DATETIME"
)
||
original
.
equals
(
"DATETIME2"
))
{
if
(
readIf
(
"("
))
{
originalScale
=
read
Posi
tiveInt
();
originalScale
=
read
NonNega
tiveInt
();
if
(
originalScale
>
ValueTime
.
MAXIMUM_SCALE
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_VALUE_SCALE_PRECISION
,
Integer
.
toString
(
originalScale
));
...
...
@@ -4506,7 +4503,7 @@ public class Parser {
}
}
else
if
(
dataType
.
type
==
Value
.
DOUBLE
&&
original
.
equals
(
"FLOAT"
))
{
if
(
readIf
(
"("
))
{
int
p
=
read
Posi
tiveInt
();
int
p
=
read
NonNega
tiveInt
();
read
(
")"
);
if
(
p
>
53
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_VALUE_SCALE_PRECISION
,
Integer
.
toString
(
p
));
...
...
@@ -4540,7 +4537,7 @@ public class Parser {
}
else
if
(
readIf
(
"("
))
{
// Support for MySQL: INT(11), MEDIUMINT(8) and so on.
// Just ignore the precision.
read
Posi
tiveInt
();
read
NonNega
tiveInt
();
read
(
")"
);
}
if
(
readIf
(
"FOR"
))
{
...
...
@@ -4793,7 +4790,7 @@ public class Parser {
Select
command
=
new
Select
(
session
);
currentSelect
=
command
;
TableFilter
filter
=
parseValuesTable
(
0
);
ArrayList
<
Expression
>
list
=
Utils
.
newSmallArrayList
(
);
ArrayList
<
Expression
>
list
=
new
ArrayList
<>(
1
);
list
.
add
(
new
Wildcard
(
null
,
null
));
command
.
setExpressions
(
list
);
command
.
addTableFilter
(
filter
,
true
);
...
...
@@ -5087,7 +5084,7 @@ public class Parser {
command
.
setRowBased
(
false
);
}
if
(
readIf
(
"QUEUE"
))
{
command
.
setQueueSize
(
read
Posi
tiveInt
());
command
.
setQueueSize
(
read
NonNega
tiveInt
());
}
command
.
setNoWait
(
readIf
(
"NOWAIT"
));
if
(
readIf
(
"AS"
))
{
...
...
@@ -5170,7 +5167,7 @@ public class Parser {
viewsCreated
.
add
(
parseSingleCommonTableExpression
(
isPersistent
));
}
while
(
readIf
(
","
));
Prepared
p
=
null
;
Prepared
p
;
// reverse the order of constructed CTE views - as the destruction order
// (since later created view may depend on previously created views -
// we preserve that dependency order in the destruction sequence )
...
...
@@ -5218,7 +5215,6 @@ public class Parser {
private
TableView
parseSingleCommonTableExpression
(
boolean
isPersistent
)
{
String
cteViewName
=
readIdentifierWithSchema
();
Schema
schema
=
getSchema
();
Table
recursiveTable
=
null
;
ArrayList
<
Column
>
columns
=
Utils
.
newSmallArrayList
();
String
[]
cols
=
null
;
...
...
@@ -5233,7 +5229,7 @@ public class Parser {
}
}
Table
oldViewFound
=
null
;
Table
oldViewFound
;
if
(
isPersistent
)
{
oldViewFound
=
getSchema
().
findTableOrView
(
session
,
cteViewName
);
}
else
{
...
...
@@ -5265,7 +5261,7 @@ public class Parser {
* work (its removed after creation in this method). Only create table
* data and table if we don't have a working CTE already.
*/
recursiveTable
=
TableView
.
createShadowTableForRecursiveTableExpression
(
Table
recursiveTable
=
TableView
.
createShadowTableForRecursiveTableExpression
(
isPersistent
,
session
,
cteViewName
,
schema
,
columns
,
database
);
List
<
Column
>
columnTemplateList
;
String
[]
querySQLOutput
=
{
null
};
...
...
@@ -5653,7 +5649,7 @@ public class Parser {
}
else
if
(
readIf
(
"NUMBERS"
))
{
command
.
setInt
(
Constants
.
ALLOW_LITERALS_NUMBERS
);
}
else
{
command
.
setInt
(
read
Posi
tiveInt
());
command
.
setInt
(
read
NonNega
tiveInt
());
}
return
command
;
}
else
if
(
readIf
(
"DEFAULT_TABLE_TYPE"
))
{
...
...
@@ -5664,7 +5660,7 @@ public class Parser {
}
else
if
(
readIf
(
"CACHED"
))
{
command
.
setInt
(
Table
.
TYPE_CACHED
);
}
else
{
command
.
setInt
(
read
Posi
tiveInt
());
command
.
setInt
(
read
NonNega
tiveInt
());
}
return
command
;
}
else
if
(
readIf
(
"CREATE"
))
{
...
...
@@ -6163,7 +6159,7 @@ public class Parser {
// Oracle specifies (but will not require) an opening parenthesis
boolean
hasOpeningBracket
=
readIf
(
"("
);
String
columnName
=
readColumnIdentifier
();
AlterTableAlterColumn
command
=
null
;
AlterTableAlterColumn
command
;
NullConstraintType
nullConstraint
=
parseNotNullConstraint
();
switch
(
nullConstraint
)
{
case
NULL_IS_ALLOWED:
...
...
h2/src/main/org/h2/command/dml/MergeUsing.java
浏览文件 @
47ff9145
...
...
@@ -390,31 +390,21 @@ public class MergeUsing extends Prepared {
query
.
prepare
();
}
int
embeddedStatementsCount
=
0
;
// Prepare each of the sub-commands ready to aid in the MERGE
// collaboration
if
(
updateCommand
!=
null
)
{
updateCommand
.
setSourceTableFilter
(
sourceTableFilter
);
updateCommand
.
setCondition
(
appendOnCondition
(
updateCommand
));
updateCommand
.
prepare
();
embeddedStatementsCount
++;
}
if
(
deleteCommand
!=
null
)
{
deleteCommand
.
setSourceTableFilter
(
sourceTableFilter
);
deleteCommand
.
setCondition
(
appendOnCondition
(
deleteCommand
));
deleteCommand
.
prepare
();
embeddedStatementsCount
++;
}
if
(
insertCommand
!=
null
)
{
insertCommand
.
setSourceTableFilter
(
sourceTableFilter
);
insertCommand
.
prepare
();
embeddedStatementsCount
++;
}
if
(
embeddedStatementsCount
==
0
)
{
throw
DbException
.
get
(
ErrorCode
.
SYNTAX_ERROR_1
,
"At least UPDATE, DELETE or INSERT embedded statement must be supplied."
);
}
// setup the targetMatchQuery - for detecting if the target row exists
...
...
h2/src/test/org/h2/test/db/TestMergeUsing.java
浏览文件 @
47ff9145
...
...
@@ -161,7 +161,7 @@ public class TestMergeUsing extends TestBase implements Trigger {
GATHER_ORDERED_RESULTS_SQL
,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) WHERE X<0"
,
0
,
"
At least UPDATE, DELETE or INSERT embedded statement must be supplied.
"
);
"
expected \"WHEN\"
"
);
// Two updates to same row - update and delete together - emptying the
// parent table
testMergeUsing
(
...
...
h2/src/test/org/h2/test/scripts/dml/mergeUsing.sql
浏览文件 @
47ff9145
...
...
@@ -149,3 +149,29 @@ SELECT * FROM TEST ORDER BY C1, C2;
DROP
TABLE
TEST
;
>
ok
CREATE
TABLE
TEST
(
ID
INT
,
VALUE
INT
);
>
ok
MERGE
INTO
TEST
USING
DUAL
ON
(
ID
=
1
)
WHEN
MATCHED
THEN
UPDATE
SET
VALUE
=
1
WHEN
;
>
exception
SYNTAX_ERROR_2
MERGE
INTO
TEST
USING
DUAL
ON
(
ID
=
1
)
WHEN
MATCHED
THEN
UPDATE
SET
VALUE
=
1
WHEN
NOT
MATCHED
THEN
;
>
exception
SYNTAX_ERROR_2
MERGE
INTO
TEST
USING
DUAL
ON
(
ID
=
1
)
WHEN
NOT
MATCHED
THEN
INSERT
(
ID
,
VALUE
)
VALUES
(
1
,
1
)
WHEN
;
>
exception
SYNTAX_ERROR_2
MERGE
INTO
TEST
USING
DUAL
ON
(
ID
=
1
)
WHEN
NOT
MATCHED
THEN
INSERT
(
ID
,
VALUE
)
VALUES
(
1
,
1
)
WHEN
MATCHED
THEN
;
>
exception
SYNTAX_ERROR_2
DROP
TABLE
TEST
;
>
ok
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论