提交 8c52436a authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Remove only one target row match restriction from MERGE USING

上级 e9a303fb
...@@ -21,6 +21,8 @@ Change Log ...@@ -21,6 +21,8 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>Issue #1493: MERGE statement fails when it updates more than one row
</li>
<li>Issue #1491: Unnecessary restriction on MERGE USING statement when ON predicate doesn't match inserted row <li>Issue #1491: Unnecessary restriction on MERGE USING statement when ON predicate doesn't match inserted row
</li> </li>
<li>Issue #1490: NullPointerException when running invalid MERGE statement <li>Issue #1490: NullPointerException when running invalid MERGE statement
......
...@@ -219,45 +219,29 @@ public class MergeUsing extends Prepared { ...@@ -219,45 +219,29 @@ public class MergeUsing extends Prepared {
} }
private boolean isTargetRowFound() { private boolean isTargetRowFound() {
boolean matched = false;
try (ResultInterface rows = targetMatchQuery.query(0)) { try (ResultInterface rows = targetMatchQuery.query(0)) {
if (!rows.next()) { while (rows.next()) {
return false; Value targetRowId = rows.currentRow()[0];
} Integer number = targetRowidsRemembered.get(targetRowId);
Value targetRowId = rows.currentRow()[0]; // throw and exception if we have processed this _ROWID_ before...
Integer number = targetRowidsRemembered.get(targetRowId); if (number != null) {
// throw and exception if we have processed this _ROWID_ before... throw DbException.get(ErrorCode.DUPLICATE_KEY_1,
if (number != null) { "Merge using ON column expression, " +
throw DbException.get(ErrorCode.DUPLICATE_KEY_1, "duplicate _ROWID_ target record already updated, deleted or inserted:_ROWID_="
"Merge using ON column expression, " + + targetRowId + ":in:"
"duplicate _ROWID_ target record already updated, deleted or inserted:_ROWID_=" + targetTableFilter.getTable()
+ targetRowId + ":in:" + ":conflicting source row number:"
+ targetTableFilter.getTable() + number);
+ ":conflicting source row number:"
+ number);
}
// remember the source column values we have used before (they
// are the effective ON clause keys
// and should not be repeated
targetRowidsRemembered.put(targetRowId, sourceQueryRowNumber);
if (rows.next()) {
int rowCount;
if (rows.isLazy()) {
for (rowCount = 2; rows.next(); rowCount++) {
}
} else {
rowCount = rows.getRowCount();
} }
throw DbException.get(ErrorCode.DUPLICATE_KEY_1, // remember the source column values we have used before (they
"Duplicate key updated " // are the effective ON clause keys
+ rowCount // and should not be repeated
+ " rows at once, only 1 expected:_ROWID_=" targetRowidsRemembered.put(targetRowId, sourceQueryRowNumber);
+ targetRowId + ":in:" matched = true;
+ targetTableFilter.getTable()
+ ":conflicting source row number:"
+ targetRowidsRemembered.get(targetRowId));
} }
return true;
} }
return matched;
} }
// Use the regular merge syntax as our plan SQL // Use the regular merge syntax as our plan SQL
......
...@@ -196,18 +196,6 @@ public class TestMergeUsing extends TestDb implements Trigger { ...@@ -196,18 +196,6 @@ public class TestMergeUsing extends TestDb implements Trigger {
"SELECT 1 AS ID, 'Marcy'||X||X UNION ALL SELECT 1 AS ID, 'Marcy2'", "SELECT 1 AS ID, 'Marcy'||X||X UNION ALL SELECT 1 AS ID, 'Marcy2'",
2); 2);
// Duplicate key updated 3 rows at once, only 1 expected
testMergeUsingException(
"CREATE TABLE PARENT AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );"
+ "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );",
"MERGE INTO PARENT USING SOURCE ON (PARENT.ID = SOURCE.ID) WHEN MATCHED THEN " +
"UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 " +
"DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN " +
"INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)",
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, "Duplicate key updated 3 rows at once, only 1 expected");
// Missing target columns in ON expression // Missing target columns in ON expression
testMergeUsingException( testMergeUsingException(
"CREATE TABLE PARENT AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );" "CREATE TABLE PARENT AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );"
...@@ -220,18 +208,6 @@ public class TestMergeUsing extends TestDb implements Trigger { ...@@ -220,18 +208,6 @@ public class TestMergeUsing extends TestDb implements Trigger {
"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 target columns found in ON clause"); 3, "No references to target columns found in ON clause");
// Missing source columns in ON expression
testMergeUsingException(
"CREATE TABLE PARENT AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );"
+ "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );",
"MERGE INTO PARENT USING SOURCE ON (PARENT.ID = 1) WHEN MATCHED THEN " +
"UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 " +
"DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN " +
"INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)",
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, "Duplicate key updated 3 rows at once, only 1 expected");
// One insert, one update one delete happens, target table missing PK, // One insert, one update one delete happens, target table missing PK,
// triggers update all NAME fields // triggers update all NAME fields
triggerTestingUpdateCount = 0; triggerTestingUpdateCount = 0;
......
...@@ -233,5 +233,18 @@ SELECT * FROM TEST; ...@@ -233,5 +233,18 @@ SELECT * FROM TEST;
> 3 30 > 3 30
> rows: 3 > rows: 3
MERGE INTO TEST USING (SELECT 1) ON (ID = ID)
WHEN MATCHED THEN UPDATE SET VALUE = 40
WHEN NOT MATCHED THEN INSERT VALUES (4, 40);
> update count: 3
SELECT * FROM TEST;
> ID VALUE
> -- -----
> 1 40
> 2 40
> 3 40
> rows: 3
DROP TABLE TEST; DROP TABLE TEST;
> ok > ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论