提交 acc1f300 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Remove restriction for presense of columns in ON clause of MERGE USING

上级 8c52436a
......@@ -23,6 +23,8 @@ Change Log
<ul>
<li>Issue #1493: MERGE statement fails when it updates more than one row
</li>
<li>Issue #1492: Unnecessary restriction on MERGE USING statement when ON clause doesn't reference any target table columns
</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
......
......@@ -7,7 +7,6 @@ package org.h2.command.dml;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import org.h2.api.ErrorCode;
import org.h2.api.Trigger;
......@@ -18,7 +17,6 @@ import org.h2.engine.Session;
import org.h2.expression.ConditionAndOr;
import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn;
import org.h2.expression.ExpressionVisitor;
import org.h2.message.DbException;
import org.h2.result.ResultInterface;
import org.h2.result.Row;
......@@ -102,7 +100,6 @@ public class MergeUsing extends Prepared {
private Table targetTable;
private TableFilter targetTableFilter;
private Column[] columns;
private Column[] keys;
private final ArrayList<Expression[]> valuesExpressionList = Utils.newSmallArrayList();
private Query query;
......@@ -253,17 +250,7 @@ public class MergeUsing extends Prepared {
buff.appendExceptFirst(", ");
buff.append(c.getSQL());
}
buff.append(')');
if (keys != null) {
buff.append(" KEY(");
buff.resetCount();
for (Column c : keys) {
buff.appendExceptFirst(", ");
buff.append(c.getSQL());
}
buff.append(')');
}
buff.append('\n');
buff.append(')').append('\n');
if (!valuesExpressionList.isEmpty()) {
buff.append("VALUES ");
int row = 0;
......@@ -297,15 +284,6 @@ public class MergeUsing extends Prepared {
onCondition.mapColumns(sourceTableFilter, 2, Expression.MAP_INITIAL);
onCondition.mapColumns(targetTableFilter, 1, Expression.MAP_INITIAL);
if (keys == null) {
keys = buildColumnListFromOnCondition(targetTableFilter.getTable());
}
if (keys.length == 0) {
throw DbException.get(ErrorCode.COLUMN_NOT_FOUND_1,
"No references to target columns found in ON clause:"
+ targetTableFilter.toString());
}
// only do the optimize now - before we have already gathered the
// unoptimized column data
onCondition = onCondition.optimize(session);
......@@ -367,13 +345,6 @@ public class MergeUsing extends Prepared {
targetMatchQuery.prepare();
}
private Column[] buildColumnListFromOnCondition(Table table) {
HashSet<Column> columns = new HashSet<>();
ExpressionVisitor visitor = ExpressionVisitor.getColumnsVisitor(columns, table);
onCondition.isEverything(visitor);
return columns.toArray(new Column[0]);
}
private Expression appendOnCondition(Update updateCommand) {
if (updateCommand.getCondition() == null) {
return onCondition;
......
......@@ -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);
// Missing target 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 (1 = 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, "No references to target columns found in ON clause");
// One insert, one update one delete happens, target table missing PK,
// triggers update all NAME fields
triggerTestingUpdateCount = 0;
......
......@@ -29,7 +29,7 @@ EXPLAIN PLAN
UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT
MATCHED THEN
INSERT (ID, NAME) VALUES (S.ID, S.NAME);
>> MERGE INTO PUBLIC.PARENT(ID, NAME) KEY(ID) SELECT X AS ID, ('Coco' || X) AS NAME FROM SYSTEM_RANGE(1, 2) /* PUBLIC.RANGE_INDEX */
>> MERGE INTO PUBLIC.PARENT(ID, NAME) SELECT X AS ID, ('Coco' || X) AS NAME FROM SYSTEM_RANGE(1, 2) /* PUBLIC.RANGE_INDEX */
DROP TABLE PARENT;
> ok
......@@ -246,5 +246,18 @@ SELECT * FROM TEST;
> 3 40
> rows: 3
MERGE INTO TEST USING (SELECT 1) ON (1 = 1)
WHEN MATCHED THEN UPDATE SET VALUE = 50
WHEN NOT MATCHED THEN INSERT VALUES (5, 50);
> update count: 3
SELECT * FROM TEST;
> ID VALUE
> -- -----
> 1 50
> 2 50
> 3 50
> rows: 3
DROP TABLE TEST;
> ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论