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

Merge pull request #1155 from katzyn/merge_using

Fix different issues with MERGE USING
......@@ -1168,11 +1168,33 @@ public class Parser {
command.setOnCondition(condition);
read(")");
if (readIfAll("WHEN", "MATCHED", "THEN")) {
boolean matched = parseWhenMatched(command);
if (parseWhenNotMatched(command) && !matched) {
parseWhenMatched(command);
}
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;
}
private boolean parseWhenMatched(MergeUsing command) {
if (!readIfAll("WHEN", "MATCHED", "THEN")) {
return false;
}
int startMatched = lastParseIndex;
if (readIf("UPDATE")) {
Update updateCommand = new Update(session);
//currentPrepared = updateCommand;
TableFilter filter = command.getTargetTableFilter();
updateCommand.setTableFilter(filter);
parseUpdateSetClause(updateCommand, filter, startMatched);
......@@ -1186,34 +1208,29 @@ public class Parser {
parseDeleteGivenTable(deleteCommand, null, startMatched);
command.setDeleteCommand(deleteCommand);
}
return true;
}
private boolean parseWhenNotMatched(MergeUsing command) {
if (!readIfAll("WHEN", "NOT", "MATCHED", "THEN")) {
return false;
}
if (readIfAll("WHEN", "NOT", "MATCHED", "THEN")) {
if (readIf("INSERT")) {
Insert insertCommand = new Insert(session);
insertCommand.setTable(command.getTargetTable());
parseInsertGivenTable(insertCommand, command.getTargetTable());
command.setInsertCommand(insertCommand);
}
}
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 true;
}
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));
}
......@@ -1460,7 +1477,7 @@ public class Parser {
table = new FunctionTable(mainSchema, session, expr, call);
}
} else {
table = readTableOrView(tableName, true);
table = readTableOrView(tableName);
}
}
ArrayList<String> derivedColumnNames = null;
......@@ -5908,10 +5925,10 @@ public class Parser {
}
private Table readTableOrView() {
return readTableOrView(readIdentifierWithSchema(null), false);
return readTableOrView(readIdentifierWithSchema(null));
}
private Table readTableOrView(String tableName, boolean allowDual) {
private Table readTableOrView(String tableName) {
if (schemaName != null) {
Table table = getSchema().resolveTableOrView(session, tableName);
if (table != null) {
......@@ -5934,7 +5951,7 @@ public class Parser {
}
}
}
if (allowDual && isDualTable(tableName)) {
if (isDualTable(tableName)) {
return getDualTable(false);
}
throw DbException.get(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, tableName);
......
......@@ -113,7 +113,6 @@ public class MergeUsing extends Prepared {
private Insert insertCommand;
private String queryAlias;
private int countUpdatedRows;
private Column[] sourceKeys;
private Select targetMatchQuery;
private final HashMap<Value, Integer> targetRowidsRemembered = new HashMap<>();
private int sourceQueryRowNumber;
......@@ -358,16 +357,6 @@ public class MergeUsing extends Prepared {
"No references to target columns found in ON clause:"
+ targetTableFilter.toString());
}
if (sourceKeys == null) {
HashSet<Column> sourceColumns = buildColumnListFromOnCondition(
sourceTableFilter);
sourceKeys = sourceColumns.toArray(new Column[0]);
}
if (sourceKeys.length == 0) {
throw DbException.get(ErrorCode.COLUMN_NOT_FOUND_1,
"No references to source columns found in ON clause:"
+ sourceTableFilter.toString());
}
// only do the optimize now - before we have already gathered the
// unoptimized column data
......
......@@ -245,7 +245,7 @@ public class TestMergeUsing extends TestBase implements Trigger {
GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL " +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)",
3, "No references to source columns found in ON clause");
3, "Duplicate key updated 3 rows at once, only 1 expected");
// Insert does not insert correct values with respect to ON condition
// (inserts ID value above 100, instead)
testMergeUsingException(
......
......@@ -114,3 +114,38 @@ DROP TABLE SOURCE_TABLE;
DROP TABLE DEST_TABLE;
> ok
CREATE TABLE TEST(C1 INT, C2 INT, C3 INT);
> ok
MERGE INTO TEST USING DUAL ON (C1 = 11 AND C2 = 21)
WHEN NOT MATCHED THEN INSERT (C1, C2, C3) VALUES (11, 21, 31)
WHEN MATCHED THEN UPDATE SET C3 = 31;
> update count: 1
MERGE INTO TEST USING DUAL ON (C1 = 11 AND C2 = 22)
WHEN NOT MATCHED THEN INSERT (C1, C2, C3) VALUES (11, 22, 32)
WHEN MATCHED THEN UPDATE SET C3 = 32;
> update count: 1
SELECT * FROM TEST ORDER BY C1, C2;
> C1 C2 C3
> -- -- --
> 11 21 31
> 11 22 32
> rows (ordered): 2
MERGE INTO TEST USING DUAL ON (C1 = 11 AND C2 = 21)
WHEN NOT MATCHED THEN INSERT (C1, C2, C3) VALUES (11, 21, 33)
WHEN MATCHED THEN UPDATE SET C3 = 33;
> update count: 1
SELECT * FROM TEST ORDER BY C1, C2;
> C1 C2 C3
> -- -- --
> 11 21 33
> 11 22 32
> rows (ordered): 2
DROP TABLE TEST;
> ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论