Unverified 提交 a7e9c1aa authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1379 from katzyn/mergeUsing

Fix MERGE USING with parameters
...@@ -1494,17 +1494,6 @@ public class Parser { ...@@ -1494,17 +1494,6 @@ public class Parser {
} }
setSQL(command, "MERGE", start); setSQL(command, "MERGE", start);
// build and prepare the targetMatchQuery ready to test each rows
// existence in the target table (using source row to match)
StringBuilder targetMatchQuerySQL = new StringBuilder("SELECT _ROWID_ FROM ");
appendTableWithSchemaAndAlias(targetMatchQuerySQL, command.getTargetTable(),
command.getTargetTableFilter().getTableAlias());
targetMatchQuerySQL
.append(" WHERE ").append(command.getOnCondition().getSQL());
command.setTargetMatchQuery(
(Select) parse(targetMatchQuerySQL.toString()));
return command; return command;
} }
...@@ -1548,18 +1537,6 @@ public class Parser { ...@@ -1548,18 +1537,6 @@ public class Parser {
} }
} }
private static void appendTableWithSchemaAndAlias(StringBuilder buff, Table table, String alias) {
if (table instanceof RangeTable) {
buff.append(table.getSQL());
} else {
buff.append(quoteIdentifier(table.getSchema().getName()))
.append('.').append(quoteIdentifier(table.getName()));
}
if (alias != null) {
buff.append(" AS ").append(quoteIdentifier(alias));
}
}
private Insert parseInsert() { private Insert parseInsert() {
Insert command = new Insert(session); Insert command = new Insert(session);
currentPrepared = command; currentPrepared = command;
......
...@@ -172,7 +172,7 @@ public class Merge extends Prepared { ...@@ -172,7 +172,7 @@ public class Merge extends Prepared {
p.setValue(v); p.setValue(v);
} }
// try and update // try an update
int count = update.update(); int count = update.update();
// if update fails try an insert // if update fails try an insert
......
...@@ -17,6 +17,7 @@ import org.h2.command.Prepared; ...@@ -17,6 +17,7 @@ import org.h2.command.Prepared;
import org.h2.engine.Right; import org.h2.engine.Right;
import org.h2.expression.ConditionAndOr; import org.h2.expression.ConditionAndOr;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn;
import org.h2.expression.ExpressionVisitor; import org.h2.expression.ExpressionVisitor;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
...@@ -128,6 +129,7 @@ public class MergeUsing extends Prepared { ...@@ -128,6 +129,7 @@ public class MergeUsing extends Prepared {
@Override @Override
public int update() { public int update() {
countUpdatedRows = 0;
// clear list of source table keys & rowids we have processed already // clear list of source table keys & rowids we have processed already
targetRowidsRemembered.clear(); targetRowidsRemembered.clear();
...@@ -202,41 +204,28 @@ public class MergeUsing extends Prepared { ...@@ -202,41 +204,28 @@ public class MergeUsing extends Prepared {
protected void merge(Row sourceRow) { protected void merge(Row sourceRow) {
// put the column values into the table filter // put the column values into the table filter
sourceTableFilter.set(sourceRow); sourceTableFilter.set(sourceRow);
if (isTargetRowFound()) {
// Is the target row there already ?
boolean rowFound = isTargetRowFound();
// try and perform an update
int rowUpdateCount = 0;
if (rowFound) {
if (updateCommand != null) { if (updateCommand != null) {
rowUpdateCount += updateCommand.update(); countUpdatedRows += updateCommand.update();
} }
// under oracle rules these updates & delete combinations are
// allowed together
if (deleteCommand != null) { if (deleteCommand != null) {
int deleteRowUpdateCount = deleteCommand.update(); countUpdatedRows += deleteCommand.update();
// under oracle rules these updates & delete combinations are
// allowed together
if (rowUpdateCount == 1 && deleteRowUpdateCount == 1) {
countUpdatedRows += deleteRowUpdateCount;
deleteRowUpdateCount = 0;
} else {
rowUpdateCount += deleteRowUpdateCount;
}
} }
} else { } else {
// if either updates do nothing, try an insert if (insertCommand != null) {
if (rowUpdateCount == 0) { int count = insertCommand.update();
rowUpdateCount += addRowByCommandInsert(sourceRow); if (!isTargetRowFound()) {
} else if (rowUpdateCount != 1) { throw DbException.get(ErrorCode.GENERAL_ERROR_1,
throw DbException.get(ErrorCode.DUPLICATE_KEY_1, "Expected to find key after row inserted, but none found. "
"Duplicate key inserted " + rowUpdateCount + "Insert does not match ON condition.:"
+ " rows at once, only 1 expected:" + targetTable.getSQL() + ":source row="
+ targetTable.getSQL()); + Arrays.asList(sourceRow.getValueList()));
}
countUpdatedRows += count;
} }
} }
countUpdatedRows += rowUpdateCount;
} }
private boolean isTargetRowFound() { private boolean isTargetRowFound() {
...@@ -281,20 +270,6 @@ public class MergeUsing extends Prepared { ...@@ -281,20 +270,6 @@ public class MergeUsing extends Prepared {
} }
} }
private int addRowByCommandInsert(Row sourceRow) {
int localCount = 0;
if (insertCommand != null) {
localCount += insertCommand.update();
if (!isTargetRowFound()) {
throw DbException.get(ErrorCode.GENERAL_ERROR_1,
"Expected to find key after row inserted, but none found. Insert does not match ON condition.:"
+ targetTable.getSQL() + ":source row="
+ Arrays.asList(sourceRow.getValueList()));
}
}
return localCount;
}
// Use the regular merge syntax as our plan SQL // Use the regular merge syntax as our plan SQL
@Override @Override
public String getPlanSQL() { public String getPlanSQL() {
...@@ -407,11 +382,14 @@ public class MergeUsing extends Prepared { ...@@ -407,11 +382,14 @@ public class MergeUsing extends Prepared {
} }
// setup the targetMatchQuery - for detecting if the target row exists // setup the targetMatchQuery - for detecting if the target row exists
Expression targetMatchCondition = targetMatchQuery.getCondition(); targetMatchQuery = new Select(session);
targetMatchCondition.addFilterConditions(sourceTableFilter, true); ArrayList<Expression> expressions = new ArrayList<>(1);
targetMatchCondition.mapColumns(sourceTableFilter, 2); expressions.add(new ExpressionColumn(session.getDatabase(), targetTable.getSchema().getName(),
targetMatchCondition = targetMatchCondition.optimize(session); targetTableFilter.getTableAlias(), "_ROWID_"));
targetMatchCondition.createIndexConditions(session, sourceTableFilter); targetMatchQuery.setExpressions(expressions);
targetMatchQuery.addTableFilter(targetTableFilter, true);
targetMatchQuery.addCondition(onCondition);
targetMatchQuery.init();
targetMatchQuery.prepare(); targetMatchQuery.prepare();
} }
...@@ -512,14 +490,6 @@ public class MergeUsing extends Prepared { ...@@ -512,14 +490,6 @@ public class MergeUsing extends Prepared {
this.targetTable = targetTable; this.targetTable = targetTable;
} }
public Select getTargetMatchQuery() {
return targetMatchQuery;
}
public void setTargetMatchQuery(Select targetMatchQuery) {
this.targetMatchQuery = targetMatchQuery;
}
// Prepared interface implementations // Prepared interface implementations
@Override @Override
......
...@@ -187,3 +187,26 @@ MERGE INTO TEST USING DUAL ON (ID = 1) ...@@ -187,3 +187,26 @@ MERGE INTO TEST USING DUAL ON (ID = 1)
DROP TABLE TEST; DROP TABLE TEST;
> ok > ok
CREATE TABLE TEST(ID INT PRIMARY KEY);
> ok
MERGE INTO TEST USING (SELECT CAST(? AS INT) ID FROM DUAL) S ON (TEST.ID = S.ID)
WHEN NOT MATCHED THEN INSERT (ID) VALUES (S.ID);
{
10
20
30
};
> update count: 3
SELECT * FROM TEST;
> ID
> --
> 10
> 20
> 30
> rows: 3
DROP TABLE TEST;
> ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论