提交 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
<h2>Next Version (unreleased)</h2>
<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>
<li>Issue #1490: NullPointerException when running invalid MERGE statement
......
......@@ -219,45 +219,29 @@ public class MergeUsing extends Prepared {
}
private boolean isTargetRowFound() {
boolean matched = false;
try (ResultInterface rows = targetMatchQuery.query(0)) {
if (!rows.next()) {
return false;
}
Value targetRowId = rows.currentRow()[0];
Integer number = targetRowidsRemembered.get(targetRowId);
// throw and exception if we have processed this _ROWID_ before...
if (number != null) {
throw DbException.get(ErrorCode.DUPLICATE_KEY_1,
"Merge using ON column expression, " +
"duplicate _ROWID_ target record already updated, deleted or inserted:_ROWID_="
+ targetRowId + ":in:"
+ targetTableFilter.getTable()
+ ":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();
while (rows.next()) {
Value targetRowId = rows.currentRow()[0];
Integer number = targetRowidsRemembered.get(targetRowId);
// throw and exception if we have processed this _ROWID_ before...
if (number != null) {
throw DbException.get(ErrorCode.DUPLICATE_KEY_1,
"Merge using ON column expression, " +
"duplicate _ROWID_ target record already updated, deleted or inserted:_ROWID_="
+ targetRowId + ":in:"
+ targetTableFilter.getTable()
+ ":conflicting source row number:"
+ number);
}
throw DbException.get(ErrorCode.DUPLICATE_KEY_1,
"Duplicate key updated "
+ rowCount
+ " rows at once, only 1 expected:_ROWID_="
+ targetRowId + ":in:"
+ targetTableFilter.getTable()
+ ":conflicting source row number:"
+ targetRowidsRemembered.get(targetRowId));
// 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);
matched = true;
}
return true;
}
return matched;
}
// Use the regular merge syntax as our plan SQL
......
......@@ -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'",
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
testMergeUsingException(
"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 {
"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 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,
// triggers update all NAME fields
triggerTestingUpdateCount = 0;
......
......@@ -233,5 +233,18 @@ SELECT * FROM TEST;
> 3 30
> 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;
> ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论