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 { ...@@ -1168,11 +1168,33 @@ public class Parser {
command.setOnCondition(condition); command.setOnCondition(condition);
read(")"); 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; int startMatched = lastParseIndex;
if (readIf("UPDATE")) { if (readIf("UPDATE")) {
Update updateCommand = new Update(session); Update updateCommand = new Update(session);
//currentPrepared = updateCommand;
TableFilter filter = command.getTargetTableFilter(); TableFilter filter = command.getTargetTableFilter();
updateCommand.setTableFilter(filter); updateCommand.setTableFilter(filter);
parseUpdateSetClause(updateCommand, filter, startMatched); parseUpdateSetClause(updateCommand, filter, startMatched);
...@@ -1186,34 +1208,29 @@ public class Parser { ...@@ -1186,34 +1208,29 @@ public class Parser {
parseDeleteGivenTable(deleteCommand, null, startMatched); parseDeleteGivenTable(deleteCommand, null, startMatched);
command.setDeleteCommand(deleteCommand); 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")) { if (readIf("INSERT")) {
Insert insertCommand = new Insert(session); Insert insertCommand = new Insert(session);
insertCommand.setTable(command.getTargetTable()); insertCommand.setTable(command.getTargetTable());
parseInsertGivenTable(insertCommand, command.getTargetTable()); parseInsertGivenTable(insertCommand, command.getTargetTable());
command.setInsertCommand(insertCommand); command.setInsertCommand(insertCommand);
} }
} return true;
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 static void appendTableWithSchemaAndAlias(StringBuilder buff, Table table, String alias) { 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())) buff.append(quoteIdentifier(table.getSchema().getName()))
.append('.').append(quoteIdentifier(table.getName())); .append('.').append(quoteIdentifier(table.getName()));
}
if (alias != null) { if (alias != null) {
buff.append(" AS ").append(quoteIdentifier(alias)); buff.append(" AS ").append(quoteIdentifier(alias));
} }
...@@ -1460,7 +1477,7 @@ public class Parser { ...@@ -1460,7 +1477,7 @@ public class Parser {
table = new FunctionTable(mainSchema, session, expr, call); table = new FunctionTable(mainSchema, session, expr, call);
} }
} else { } else {
table = readTableOrView(tableName, true); table = readTableOrView(tableName);
} }
} }
ArrayList<String> derivedColumnNames = null; ArrayList<String> derivedColumnNames = null;
...@@ -5908,10 +5925,10 @@ public class Parser { ...@@ -5908,10 +5925,10 @@ public class Parser {
} }
private Table readTableOrView() { 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) { if (schemaName != null) {
Table table = getSchema().resolveTableOrView(session, tableName); Table table = getSchema().resolveTableOrView(session, tableName);
if (table != null) { if (table != null) {
...@@ -5934,7 +5951,7 @@ public class Parser { ...@@ -5934,7 +5951,7 @@ public class Parser {
} }
} }
} }
if (allowDual && isDualTable(tableName)) { if (isDualTable(tableName)) {
return getDualTable(false); return getDualTable(false);
} }
throw DbException.get(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, tableName); throw DbException.get(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, tableName);
......
...@@ -113,7 +113,6 @@ public class MergeUsing extends Prepared { ...@@ -113,7 +113,6 @@ public class MergeUsing extends Prepared {
private Insert insertCommand; private Insert insertCommand;
private String queryAlias; private String queryAlias;
private int countUpdatedRows; private int countUpdatedRows;
private Column[] sourceKeys;
private Select targetMatchQuery; private Select targetMatchQuery;
private final HashMap<Value, Integer> targetRowidsRemembered = new HashMap<>(); private final HashMap<Value, Integer> targetRowidsRemembered = new HashMap<>();
private int sourceQueryRowNumber; private int sourceQueryRowNumber;
...@@ -358,16 +357,6 @@ public class MergeUsing extends Prepared { ...@@ -358,16 +357,6 @@ public class MergeUsing extends Prepared {
"No references to target columns found in ON clause:" "No references to target columns found in ON clause:"
+ targetTableFilter.toString()); + 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 // only do the optimize now - before we have already gathered the
// unoptimized column data // unoptimized column data
......
...@@ -245,7 +245,7 @@ public class TestMergeUsing extends TestBase implements Trigger { ...@@ -245,7 +245,7 @@ public class TestMergeUsing extends TestBase implements Trigger {
GATHER_ORDERED_RESULTS_SQL, 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||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL " +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)", "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 // Insert does not insert correct values with respect to ON condition
// (inserts ID value above 100, instead) // (inserts ID value above 100, instead)
testMergeUsingException( testMergeUsingException(
......
...@@ -114,3 +114,38 @@ DROP TABLE SOURCE_TABLE; ...@@ -114,3 +114,38 @@ DROP TABLE SOURCE_TABLE;
DROP TABLE DEST_TABLE; DROP TABLE DEST_TABLE;
> ok > 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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论