提交 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 ...@@ -23,6 +23,8 @@ Change Log
<ul> <ul>
<li>Issue #1493: MERGE statement fails when it updates more than one row <li>Issue #1493: MERGE statement fails when it updates more than one row
</li> </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>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
......
...@@ -7,7 +7,6 @@ package org.h2.command.dml; ...@@ -7,7 +7,6 @@ package org.h2.command.dml;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.api.Trigger; import org.h2.api.Trigger;
...@@ -18,7 +17,6 @@ import org.h2.engine.Session; ...@@ -18,7 +17,6 @@ import org.h2.engine.Session;
import org.h2.expression.ConditionAndOr; import org.h2.expression.ConditionAndOr;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn; import org.h2.expression.ExpressionColumn;
import org.h2.expression.ExpressionVisitor;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.result.Row; import org.h2.result.Row;
...@@ -102,7 +100,6 @@ public class MergeUsing extends Prepared { ...@@ -102,7 +100,6 @@ public class MergeUsing extends Prepared {
private Table targetTable; private Table targetTable;
private TableFilter targetTableFilter; private TableFilter targetTableFilter;
private Column[] columns; private Column[] columns;
private Column[] keys;
private final ArrayList<Expression[]> valuesExpressionList = Utils.newSmallArrayList(); private final ArrayList<Expression[]> valuesExpressionList = Utils.newSmallArrayList();
private Query query; private Query query;
...@@ -253,17 +250,7 @@ public class MergeUsing extends Prepared { ...@@ -253,17 +250,7 @@ public class MergeUsing extends Prepared {
buff.appendExceptFirst(", "); buff.appendExceptFirst(", ");
buff.append(c.getSQL()); buff.append(c.getSQL());
} }
buff.append(')'); buff.append(')').append('\n');
if (keys != null) {
buff.append(" KEY(");
buff.resetCount();
for (Column c : keys) {
buff.appendExceptFirst(", ");
buff.append(c.getSQL());
}
buff.append(')');
}
buff.append('\n');
if (!valuesExpressionList.isEmpty()) { if (!valuesExpressionList.isEmpty()) {
buff.append("VALUES "); buff.append("VALUES ");
int row = 0; int row = 0;
...@@ -297,15 +284,6 @@ public class MergeUsing extends Prepared { ...@@ -297,15 +284,6 @@ public class MergeUsing extends Prepared {
onCondition.mapColumns(sourceTableFilter, 2, Expression.MAP_INITIAL); onCondition.mapColumns(sourceTableFilter, 2, Expression.MAP_INITIAL);
onCondition.mapColumns(targetTableFilter, 1, 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 // only do the optimize now - before we have already gathered the
// unoptimized column data // unoptimized column data
onCondition = onCondition.optimize(session); onCondition = onCondition.optimize(session);
...@@ -367,13 +345,6 @@ public class MergeUsing extends Prepared { ...@@ -367,13 +345,6 @@ public class MergeUsing extends Prepared {
targetMatchQuery.prepare(); 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) { private Expression appendOnCondition(Update updateCommand) {
if (updateCommand.getCondition() == null) { if (updateCommand.getCondition() == null) {
return onCondition; return onCondition;
......
...@@ -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);
// 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, // 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;
......
...@@ -29,7 +29,7 @@ EXPLAIN PLAN ...@@ -29,7 +29,7 @@ EXPLAIN PLAN
UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT
MATCHED THEN MATCHED THEN
INSERT (ID, NAME) VALUES (S.ID, S.NAME); 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; DROP TABLE PARENT;
> ok > ok
...@@ -246,5 +246,18 @@ SELECT * FROM TEST; ...@@ -246,5 +246,18 @@ SELECT * FROM TEST;
> 3 40 > 3 40
> rows: 3 > 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; DROP TABLE TEST;
> ok > ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论