提交 0c4ecec6 authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #626 from stumc/Issue#589

Issue#589 Support MERGE INTO ... USING syntax
...@@ -21,7 +21,7 @@ OFFSET specified how many rows to skip. ...@@ -21,7 +21,7 @@ OFFSET specified how many rows to skip.
Please note using high offset values should be avoided because it can cause performance problems. Please note using high offset values should be avoided because it can cause performance problems.
SAMPLE_SIZE limits the number of rows read for aggregate queries. SAMPLE_SIZE limits the number of rows read for aggregate queries.
Multiple set operators (UNION, INTERSECT, MINUS, EXPECT) are evaluated Multiple set operators (UNION, INTERSECT, MINUS, EXCEPT) are evaluated
from left to right. For compatibility with other databases and future versions from left to right. For compatibility with other databases and future versions
of H2 please use parentheses. of H2 please use parentheses.
...@@ -122,6 +122,37 @@ key is set to 0; otherwise it is set to the new key. ...@@ -122,6 +122,37 @@ key is set to 0; otherwise it is set to the new key.
MERGE INTO TEST KEY(ID) VALUES(2, 'World') MERGE INTO TEST KEY(ID) VALUES(2, 'World')
" "
"Commands (DML)","MERGE USING","
MERGE INTO targetTableName [ [AS] targetAlias]
USING { ( select ) | sourceTableName }[ [AS] sourceAlias ]
ON ( expression )
[ WHEN MATCHED THEN [ update ] [ delete] ]
[ WHEN NOT MATCHED THEN insert ]
","
Updates or deletes existing rows, and insert rows that don't exist. The ON clause
specifies the matching column expression and must be specified. If more than one row
is updated per input row, an exception is thrown.
If the source data contains duplicate rows (specifically those columns used in the
row matching ON clause), then an exception is thrown to prevent two updates applying
to the same target row. The embedded update, delete or insert statements can not re-specify
the target table name.
","
MERGE INTO TARGET_TABLE AS T USING SOURCE_TABLE AS S
ON (T.ID = S.ID)
WHEN MATCHED THEN
UPDATE SET T.COL1 = S.COL1 WHERE T.COL2<>'FINAL'
DELETE WHERE T.COL2='FINAL'
WHEN NOT MATCHED THEN
INSERT (ID,COL1,COL2) VALUES(S.ID,S.COL1,S.COL2)
MERGE INTO TARGET_TABLE AS T USING (SELECT * FROM SOURCE_TABLE) AS S
ON (T.ID = S.ID)
WHEN MATCHED THEN
UPDATE SET T.COL1 = S.COL1 WHERE T.COL2<>'FINAL'
DELETE WHERE T.COL2='FINAL'
WHEN NOT MATCHED THEN
INSERT (ID,COL1,COL2) VALUES(S.ID,S.COL1,S.COL2)
"
"Commands (DML)","RUNSCRIPT"," "Commands (DML)","RUNSCRIPT","
RUNSCRIPT FROM fileNameString scriptCompressionEncryption RUNSCRIPT FROM fileNameString scriptCompressionEncryption
[ CHARSET charsetString ] [ CHARSET charsetString ]
......
...@@ -454,4 +454,8 @@ public abstract class Prepared { ...@@ -454,4 +454,8 @@ public abstract class Prepared {
public void setCteCleanups(List<TableView> cteCleanups) { public void setCteCleanups(List<TableView> cteCleanups) {
this.cteCleanups = cteCleanups; this.cteCleanups = cteCleanups;
} }
public Session getSession() {
return session;
}
} }
...@@ -30,30 +30,38 @@ import org.h2.value.ValueNull; ...@@ -30,30 +30,38 @@ import org.h2.value.ValueNull;
public class Delete extends Prepared { public class Delete extends Prepared {
private Expression condition; private Expression condition;
private TableFilter tableFilter; private TableFilter targetTableFilter;
/** /**
* The limit expression as specified in the LIMIT or TOP clause. * The limit expression as specified in the LIMIT or TOP clause.
*/ */
private Expression limitExpr; private Expression limitExpr;
/**
* This table filter is for MERGE..USING support - not used in stand-alone DML
*/
private TableFilter sourceTableFilter;
public Delete(Session session) { public Delete(Session session) {
super(session); super(session);
} }
public void setTableFilter(TableFilter tableFilter) { public void setTableFilter(TableFilter tableFilter) {
this.tableFilter = tableFilter; this.targetTableFilter = tableFilter;
} }
public void setCondition(Expression condition) { public void setCondition(Expression condition) {
this.condition = condition; this.condition = condition;
} }
public Expression getCondition( ) {
return this.condition;
}
@Override @Override
public int update() { public int update() {
tableFilter.startQuery(session); targetTableFilter.startQuery(session);
tableFilter.reset(); targetTableFilter.reset();
Table table = tableFilter.getTable(); Table table = targetTableFilter.getTable();
session.getUser().checkRight(table, Right.DELETE); session.getUser().checkRight(table, Right.DELETE);
table.fire(session, Trigger.DELETE, true); table.fire(session, Trigger.DELETE, true);
table.lock(session, true, false); table.lock(session, true, false);
...@@ -68,11 +76,11 @@ public class Delete extends Prepared { ...@@ -68,11 +76,11 @@ public class Delete extends Prepared {
try { try {
setCurrentRowNumber(0); setCurrentRowNumber(0);
int count = 0; int count = 0;
while (limitRows != 0 && tableFilter.next()) { while (limitRows != 0 && targetTableFilter.next()) {
setCurrentRowNumber(rows.size() + 1); setCurrentRowNumber(rows.size() + 1);
if (condition == null || Boolean.TRUE.equals( if (condition == null || Boolean.TRUE.equals(
condition.getBooleanValue(session))) { condition.getBooleanValue(session))) {
Row row = tableFilter.get(); Row row = targetTableFilter.get();
boolean done = false; boolean done = false;
if (table.fireRow()) { if (table.fireRow()) {
done = table.fireBeforeRow(session, row, null); done = table.fireBeforeRow(session, row, null);
...@@ -112,7 +120,7 @@ public class Delete extends Prepared { ...@@ -112,7 +120,7 @@ public class Delete extends Prepared {
public String getPlanSQL() { public String getPlanSQL() {
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
buff.append("DELETE "); buff.append("DELETE ");
buff.append("FROM ").append(tableFilter.getPlanSQL(false)); buff.append("FROM ").append(targetTableFilter.getPlanSQL(false));
if (condition != null) { if (condition != null) {
buff.append("\nWHERE ").append(StringUtils.unEnclose( buff.append("\nWHERE ").append(StringUtils.unEnclose(
condition.getSQL())); condition.getSQL()));
...@@ -127,15 +135,24 @@ public class Delete extends Prepared { ...@@ -127,15 +135,24 @@ public class Delete extends Prepared {
@Override @Override
public void prepare() { public void prepare() {
if (condition != null) { if (condition != null) {
condition.mapColumns(tableFilter, 0); condition.mapColumns(targetTableFilter, 0);
if(sourceTableFilter!=null){
condition.mapColumns(sourceTableFilter, 0);
}
condition = condition.optimize(session); condition = condition.optimize(session);
condition.createIndexConditions(session, tableFilter); condition.createIndexConditions(session, targetTableFilter);
}
TableFilter[] filters;
if(sourceTableFilter==null){
filters = new TableFilter[] { targetTableFilter };
}
else{
filters = new TableFilter[] { targetTableFilter, sourceTableFilter };
} }
TableFilter[] filters = new TableFilter[] { tableFilter }; PlanItem item = targetTableFilter.getBestPlanItem(session, filters, 0,
PlanItem item = tableFilter.getBestPlanItem(session, filters, 0,
ExpressionVisitor.allColumnsForTableFilters(filters)); ExpressionVisitor.allColumnsForTableFilters(filters));
tableFilter.setPlanItem(item); targetTableFilter.setPlanItem(item);
tableFilter.prepare(); targetTableFilter.prepare();
} }
@Override @Override
...@@ -162,4 +179,16 @@ public class Delete extends Prepared { ...@@ -162,4 +179,16 @@ public class Delete extends Prepared {
return true; return true;
} }
public void setSourceTableFilter(TableFilter sourceTableFilter) {
this.sourceTableFilter = sourceTableFilter;
}
public TableFilter getTableFilter() {
return targetTableFilter;
}
public TableFilter getSourceTableFilter() {
return sourceTableFilter;
}
} }
...@@ -28,6 +28,7 @@ import org.h2.result.ResultTarget; ...@@ -28,6 +28,7 @@ import org.h2.result.ResultTarget;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -46,6 +47,10 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -46,6 +47,10 @@ public class Insert extends Prepared implements ResultTarget {
private boolean sortedInsertMode; private boolean sortedInsertMode;
private int rowNumber; private int rowNumber;
private boolean insertFromSelect; private boolean insertFromSelect;
/**
* This table filter is for MERGE..USING support - not used in stand-alone DML
*/
private TableFilter sourceTableFilter;
/** /**
* For MySQL-style INSERT ... ON DUPLICATE KEY UPDATE .... * For MySQL-style INSERT ... ON DUPLICATE KEY UPDATE ....
...@@ -267,6 +272,9 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -267,6 +272,9 @@ public class Insert extends Prepared implements ResultTarget {
for (int i = 0, len = expr.length; i < len; i++) { for (int i = 0, len = expr.length; i < len; i++) {
Expression e = expr[i]; Expression e = expr[i];
if (e != null) { if (e != null) {
if(sourceTableFilter!=null){
e.mapColumns(sourceTableFilter, 0);
}
e = e.optimize(session); e = e.optimize(session);
if (e instanceof Parameter) { if (e instanceof Parameter) {
Parameter p = (Parameter) e; Parameter p = (Parameter) e;
...@@ -395,4 +403,8 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -395,4 +403,8 @@ public class Insert extends Prepared implements ResultTarget {
return condition; return condition;
} }
public void setSourceTableFilter(TableFilter sourceTableFilter) {
this.sourceTableFilter = sourceTableFilter;
}
} }
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
package org.h2.command.dml; package org.h2.command.dml;
import java.util.ArrayList; import java.util.ArrayList;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.api.Trigger; import org.h2.api.Trigger;
import org.h2.command.Command; import org.h2.command.Command;
...@@ -23,6 +22,7 @@ import org.h2.result.ResultInterface; ...@@ -23,6 +22,7 @@ import org.h2.result.ResultInterface;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -33,10 +33,11 @@ import org.h2.value.Value; ...@@ -33,10 +33,11 @@ import org.h2.value.Value;
*/ */
public class Merge extends Prepared { public class Merge extends Prepared {
private Table table; private Table targetTable;
private TableFilter targetTableFilter;
private Column[] columns; private Column[] columns;
private Column[] keys; private Column[] keys;
private final ArrayList<Expression[]> list = New.arrayList(); private final ArrayList<Expression[]> valuesExpressionList = New.arrayList();
private Query query; private Query query;
private Prepared update; private Prepared update;
...@@ -52,8 +53,8 @@ public class Merge extends Prepared { ...@@ -52,8 +53,8 @@ public class Merge extends Prepared {
} }
} }
public void setTable(Table table) { public void setTargetTable(Table targetTable) {
this.table = table; this.targetTable = targetTable;
} }
public void setColumns(Column[] columns) { public void setColumns(Column[] columns) {
...@@ -74,21 +75,22 @@ public class Merge extends Prepared { ...@@ -74,21 +75,22 @@ public class Merge extends Prepared {
* @param expr the list of values * @param expr the list of values
*/ */
public void addRow(Expression[] expr) { public void addRow(Expression[] expr) {
list.add(expr); valuesExpressionList.add(expr);
} }
@Override @Override
public int update() { public int update() {
int count; int count;
session.getUser().checkRight(table, Right.INSERT); session.getUser().checkRight(targetTable, Right.INSERT);
session.getUser().checkRight(table, Right.UPDATE); session.getUser().checkRight(targetTable, Right.UPDATE);
setCurrentRowNumber(0); setCurrentRowNumber(0);
if (list.size() > 0) { if (valuesExpressionList.size() > 0) {
// process values in list
count = 0; count = 0;
for (int x = 0, size = list.size(); x < size; x++) { for (int x = 0, size = valuesExpressionList.size(); x < size; x++) {
setCurrentRowNumber(x + 1); setCurrentRowNumber(x + 1);
Expression[] expr = list.get(x); Expression[] expr = valuesExpressionList.get(x);
Row newRow = table.getTemplateRow(); Row newRow = targetTable.getTemplateRow();
for (int i = 0, len = columns.length; i < len; i++) { for (int i = 0, len = columns.length; i < len; i++) {
Column c = columns[i]; Column c = columns[i];
int index = c.getColumnId(); int index = c.getColumnId();
...@@ -107,14 +109,15 @@ public class Merge extends Prepared { ...@@ -107,14 +109,15 @@ public class Merge extends Prepared {
count++; count++;
} }
} else { } else {
// process select data for list
ResultInterface rows = query.query(0); ResultInterface rows = query.query(0);
count = 0; count = 0;
table.fire(session, Trigger.UPDATE | Trigger.INSERT, true); targetTable.fire(session, Trigger.UPDATE | Trigger.INSERT, true);
table.lock(session, true, false); targetTable.lock(session, true, false);
while (rows.next()) { while (rows.next()) {
count++; count++;
Value[] r = rows.currentRow(); Value[] r = rows.currentRow();
Row newRow = table.getTemplateRow(); Row newRow = targetTable.getTemplateRow();
setCurrentRowNumber(count); setCurrentRowNumber(count);
for (int j = 0; j < columns.length; j++) { for (int j = 0; j < columns.length; j++) {
Column c = columns[j]; Column c = columns[j];
...@@ -129,12 +132,12 @@ public class Merge extends Prepared { ...@@ -129,12 +132,12 @@ public class Merge extends Prepared {
merge(newRow); merge(newRow);
} }
rows.close(); rows.close();
table.fire(session, Trigger.UPDATE | Trigger.INSERT, false); targetTable.fire(session, Trigger.UPDATE | Trigger.INSERT, false);
} }
return count; return count;
} }
private void merge(Row row) { protected void merge(Row row) {
ArrayList<Parameter> k = update.getParameters(); ArrayList<Parameter> k = update.getParameters();
for (int i = 0; i < columns.length; i++) { for (int i = 0; i < columns.length; i++) {
Column col = columns[i]; Column col = columns[i];
...@@ -151,16 +154,20 @@ public class Merge extends Prepared { ...@@ -151,16 +154,20 @@ public class Merge extends Prepared {
Parameter p = k.get(columns.length + i); Parameter p = k.get(columns.length + i);
p.setValue(v); p.setValue(v);
} }
// try and update
int count = update.update(); int count = update.update();
// if update fails try an insert
if (count == 0) { if (count == 0) {
try { try {
table.validateConvertUpdateSequence(session, row); targetTable.validateConvertUpdateSequence(session, row);
boolean done = table.fireBeforeRow(session, null, row); boolean done = targetTable.fireBeforeRow(session, null, row);
if (!done) { if (!done) {
table.lock(session, true, false); targetTable.lock(session, true, false);
table.addRow(session, row); targetTable.addRow(session, row);
session.log(table, UndoLogRecord.INSERT, row); session.log(targetTable, UndoLogRecord.INSERT, row);
table.fireAfterRow(session, null, row, false); targetTable.fireAfterRow(session, null, row, false);
} }
} catch (DbException e) { } catch (DbException e) {
if (e.getErrorCode() == ErrorCode.DUPLICATE_KEY_1) { if (e.getErrorCode() == ErrorCode.DUPLICATE_KEY_1) {
...@@ -179,21 +186,21 @@ public class Merge extends Prepared { ...@@ -179,21 +186,21 @@ public class Merge extends Prepared {
} }
} }
if (indexMatchesKeys) { if (indexMatchesKeys) {
throw DbException.get(ErrorCode.CONCURRENT_UPDATE_1, table.getName()); throw DbException.get(ErrorCode.CONCURRENT_UPDATE_1, targetTable.getName());
} }
} }
} }
throw e; throw e;
} }
} else if (count != 1) { } else if (count != 1) {
throw DbException.get(ErrorCode.DUPLICATE_KEY_1, table.getSQL()); throw DbException.get(ErrorCode.DUPLICATE_KEY_1, targetTable.getSQL());
} }
} }
@Override @Override
public String getPlanSQL() { public String getPlanSQL() {
StatementBuilder buff = new StatementBuilder("MERGE INTO "); StatementBuilder buff = new StatementBuilder("MERGE INTO ");
buff.append(table.getSQL()).append('('); buff.append(targetTable.getSQL()).append('(');
for (Column c : columns) { for (Column c : columns) {
buff.appendExceptFirst(", "); buff.appendExceptFirst(", ");
buff.append(c.getSQL()); buff.append(c.getSQL());
...@@ -209,10 +216,10 @@ public class Merge extends Prepared { ...@@ -209,10 +216,10 @@ public class Merge extends Prepared {
buff.append(')'); buff.append(')');
} }
buff.append('\n'); buff.append('\n');
if (list.size() > 0) { if (valuesExpressionList.size() > 0) {
buff.append("VALUES "); buff.append("VALUES ");
int row = 0; int row = 0;
for (Expression[] expr : list) { for (Expression[] expr : valuesExpressionList) {
if (row++ > 0) { if (row++ > 0) {
buff.append(", "); buff.append(", ");
} }
...@@ -237,15 +244,15 @@ public class Merge extends Prepared { ...@@ -237,15 +244,15 @@ public class Merge extends Prepared {
@Override @Override
public void prepare() { public void prepare() {
if (columns == null) { if (columns == null) {
if (list.size() > 0 && list.get(0).length == 0) { if (valuesExpressionList.size() > 0 && valuesExpressionList.get(0).length == 0) {
// special case where table is used as a sequence // special case where table is used as a sequence
columns = new Column[0]; columns = new Column[0];
} else { } else {
columns = table.getColumns(); columns = targetTable.getColumns();
} }
} }
if (list.size() > 0) { if (valuesExpressionList.size() > 0) {
for (Expression[] expr : list) { for (Expression[] expr : valuesExpressionList) {
if (expr.length != columns.length) { if (expr.length != columns.length) {
throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH); throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
} }
...@@ -263,14 +270,14 @@ public class Merge extends Prepared { ...@@ -263,14 +270,14 @@ public class Merge extends Prepared {
} }
} }
if (keys == null) { if (keys == null) {
Index idx = table.getPrimaryKey(); Index idx = targetTable.getPrimaryKey();
if (idx == null) { if (idx == null) {
throw DbException.get(ErrorCode.CONSTRAINT_NOT_FOUND_1, "PRIMARY KEY"); throw DbException.get(ErrorCode.CONSTRAINT_NOT_FOUND_1, "PRIMARY KEY");
} }
keys = idx.getColumns(); keys = idx.getColumns();
} }
StatementBuilder buff = new StatementBuilder("UPDATE "); StatementBuilder buff = new StatementBuilder("UPDATE ");
buff.append(table.getSQL()).append(" SET "); buff.append(targetTable.getSQL()).append(" SET ");
for (Column c : columns) { for (Column c : columns) {
buff.appendExceptFirst(", "); buff.appendExceptFirst(", ");
buff.append(c.getSQL()).append("=?"); buff.append(c.getSQL()).append("=?");
...@@ -305,4 +312,19 @@ public class Merge extends Prepared { ...@@ -305,4 +312,19 @@ public class Merge extends Prepared {
return true; return true;
} }
public Table getTargetTable() {
return targetTable;
}
public TableFilter getTargetTableFilter() {
return targetTableFilter;
}
public void setTargetTableFilter(TableFilter targetTableFilter) {
this.targetTableFilter = targetTableFilter;
setTargetTable(targetTableFilter.getTable());
}
} }
差异被折叠。
...@@ -168,6 +168,10 @@ public class Select extends Query { ...@@ -168,6 +168,10 @@ public class Select extends Query {
} }
} }
public Expression getCondition() {
return condition;
}
private LazyResult queryGroupSorted(int columnCount, ResultTarget result) { private LazyResult queryGroupSorted(int columnCount, ResultTarget result) {
LazyResultGroupSorted lazyResult = new LazyResultGroupSorted(expressionArray, columnCount); LazyResultGroupSorted lazyResult = new LazyResultGroupSorted(expressionArray, columnCount);
if (result == null) { if (result == null) {
......
...@@ -38,7 +38,11 @@ import org.h2.value.ValueNull; ...@@ -38,7 +38,11 @@ import org.h2.value.ValueNull;
public class Update extends Prepared { public class Update extends Prepared {
private Expression condition; private Expression condition;
private TableFilter tableFilter; private TableFilter targetTableFilter;// target of update
/**
* This table filter is for MERGE..USING support - not used in stand-alone DML
*/
private TableFilter sourceTableFilter;
/** The limit expression as specified in the LIMIT clause. */ /** The limit expression as specified in the LIMIT clause. */
private Expression limitExpr; private Expression limitExpr;
...@@ -51,13 +55,17 @@ public class Update extends Prepared { ...@@ -51,13 +55,17 @@ public class Update extends Prepared {
} }
public void setTableFilter(TableFilter tableFilter) { public void setTableFilter(TableFilter tableFilter) {
this.tableFilter = tableFilter; this.targetTableFilter = tableFilter;
} }
public void setCondition(Expression condition) { public void setCondition(Expression condition) {
this.condition = condition; this.condition = condition;
} }
public Expression getCondition( ) {
return this.condition;
}
/** /**
* Add an assignment of the form column = expression. * Add an assignment of the form column = expression.
* *
...@@ -79,11 +87,11 @@ public class Update extends Prepared { ...@@ -79,11 +87,11 @@ public class Update extends Prepared {
@Override @Override
public int update() { public int update() {
tableFilter.startQuery(session); targetTableFilter.startQuery(session);
tableFilter.reset(); targetTableFilter.reset();
RowList rows = new RowList(session); RowList rows = new RowList(session);
try { try {
Table table = tableFilter.getTable(); Table table = targetTableFilter.getTable();
session.getUser().checkRight(table, Right.UPDATE); session.getUser().checkRight(table, Right.UPDATE);
table.fire(session, Trigger.UPDATE, true); table.fire(session, Trigger.UPDATE, true);
table.lock(session, true, false); table.lock(session, true, false);
...@@ -99,14 +107,14 @@ public class Update extends Prepared { ...@@ -99,14 +107,14 @@ public class Update extends Prepared {
limitRows = v.getInt(); limitRows = v.getInt();
} }
} }
while (tableFilter.next()) { while (targetTableFilter.next()) {
setCurrentRowNumber(count+1); setCurrentRowNumber(count+1);
if (limitRows >= 0 && count >= limitRows) { if (limitRows >= 0 && count >= limitRows) {
break; break;
} }
if (condition == null || if (condition == null ||
Boolean.TRUE.equals(condition.getBooleanValue(session))) { Boolean.TRUE.equals(condition.getBooleanValue(session))) {
Row oldRow = tableFilter.get(); Row oldRow = targetTableFilter.get();
Row newRow = table.getTemplateRow(); Row newRow = table.getTemplateRow();
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
Expression newExpr = expressionMap.get(columns[i]); Expression newExpr = expressionMap.get(columns[i]);
...@@ -161,7 +169,7 @@ public class Update extends Prepared { ...@@ -161,7 +169,7 @@ public class Update extends Prepared {
@Override @Override
public String getPlanSQL() { public String getPlanSQL() {
StatementBuilder buff = new StatementBuilder("UPDATE "); StatementBuilder buff = new StatementBuilder("UPDATE ");
buff.append(tableFilter.getPlanSQL(false)).append("\nSET\n "); buff.append(targetTableFilter.getPlanSQL(false)).append("\nSET\n ");
for (int i = 0, size = columns.size(); i < size; i++) { for (int i = 0, size = columns.size(); i < size; i++) {
Column c = columns.get(i); Column c = columns.get(i);
Expression e = expressionMap.get(c); Expression e = expressionMap.get(c);
...@@ -181,21 +189,30 @@ public class Update extends Prepared { ...@@ -181,21 +189,30 @@ public class Update extends Prepared {
@Override @Override
public void prepare() { public void prepare() {
if (condition != null) { if (condition != null) {
condition.mapColumns(tableFilter, 0); condition.mapColumns(targetTableFilter, 0);
condition = condition.optimize(session); condition = condition.optimize(session);
condition.createIndexConditions(session, tableFilter); condition.createIndexConditions(session, targetTableFilter);
} }
for (int i = 0, size = columns.size(); i < size; i++) { for (int i = 0, size = columns.size(); i < size; i++) {
Column c = columns.get(i); Column c = columns.get(i);
Expression e = expressionMap.get(c); Expression e = expressionMap.get(c);
e.mapColumns(tableFilter, 0); e.mapColumns(targetTableFilter, 0);
if (sourceTableFilter!=null){
e.mapColumns(sourceTableFilter, 0);
}
expressionMap.put(c, e.optimize(session)); expressionMap.put(c, e.optimize(session));
} }
TableFilter[] filters = new TableFilter[] { tableFilter }; TableFilter[] filters;
PlanItem item = tableFilter.getBestPlanItem(session, filters, 0, if(sourceTableFilter==null){
filters = new TableFilter[] { targetTableFilter };
}
else{
filters = new TableFilter[] { targetTableFilter, sourceTableFilter };
}
PlanItem item = targetTableFilter.getBestPlanItem(session, filters, 0,
ExpressionVisitor.allColumnsForTableFilters(filters)); ExpressionVisitor.allColumnsForTableFilters(filters));
tableFilter.setPlanItem(item); targetTableFilter.setPlanItem(item);
tableFilter.prepare(); targetTableFilter.prepare();
} }
@Override @Override
...@@ -222,4 +239,11 @@ public class Update extends Prepared { ...@@ -222,4 +239,11 @@ public class Update extends Prepared {
return true; return true;
} }
public TableFilter getSourceTableFilter() {
return sourceTableFilter;
}
public void setSourceTableFilter(TableFilter sourceTableFilter) {
this.sourceTableFilter = sourceTableFilter;
}
} }
...@@ -361,7 +361,7 @@ public class Session extends SessionWithState { ...@@ -361,7 +361,7 @@ public class Session extends SessionWithState {
} }
if (localTempTables.get(table.getName()) != null) { if (localTempTables.get(table.getName()) != null) {
throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1, throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1,
table.getSQL()); table.getSQL()+" AS "+table.getName());
} }
modificationId++; modificationId++;
localTempTables.put(table.getName(), table); localTempTables.put(table.getName(), table);
......
...@@ -103,6 +103,7 @@ public class JdbcConnection extends TraceObject implements Connection, ...@@ -103,6 +103,7 @@ public class JdbcConnection extends TraceObject implements Connection,
/** /**
* INTERNAL * INTERNAL
*/ */
@SuppressWarnings("resource")// the session closable object does not leak as Eclipse warns - due to the CloseWatcher
public JdbcConnection(ConnectionInfo ci, boolean useBaseDir) public JdbcConnection(ConnectionInfo ci, boolean useBaseDir)
throws SQLException { throws SQLException {
try { try {
......
...@@ -567,8 +567,6 @@ public class TableFilter implements ColumnResolver { ...@@ -567,8 +567,6 @@ public class TableFilter implements ColumnResolver {
private void checkTimeout() { private void checkTimeout() {
session.checkCanceled(); session.checkCanceled();
// System.out.println(this.alias+ " " + table.getName() + ": " +
// scanCount);
} }
/** /**
......
...@@ -45,6 +45,7 @@ import org.h2.test.db.TestLinkedTable; ...@@ -45,6 +45,7 @@ import org.h2.test.db.TestLinkedTable;
import org.h2.test.db.TestListener; import org.h2.test.db.TestListener;
import org.h2.test.db.TestLob; import org.h2.test.db.TestLob;
import org.h2.test.db.TestMemoryUsage; import org.h2.test.db.TestMemoryUsage;
import org.h2.test.db.TestMergeUsing;
import org.h2.test.db.TestMultiConn; import org.h2.test.db.TestMultiConn;
import org.h2.test.db.TestMultiDimension; import org.h2.test.db.TestMultiDimension;
import org.h2.test.db.TestMultiThread; import org.h2.test.db.TestMultiThread;
...@@ -749,6 +750,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -749,6 +750,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest(new TestLinkedTable()); addTest(new TestLinkedTable());
addTest(new TestListener()); addTest(new TestListener());
addTest(new TestLob()); addTest(new TestLob());
addTest(new TestMergeUsing());
addTest(new TestMultiConn()); addTest(new TestMultiConn());
addTest(new TestMultiDimension()); addTest(new TestMultiDimension());
addTest(new TestMultiThreadedKernel()); addTest(new TestMultiThreadedKernel());
......
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论