提交 518f51d1 authored 作者: Owner's avatar Owner

Basic empty table case works with lots of debug.

上级 aac577cc
......@@ -739,33 +739,17 @@ public class Parser {
return filter.getTable().getColumn(columnName);
}
// TODO:(SM) parseUpdate
private Update parseUpdate() {
Update command = new Update(session);
currentPrepared = command;
int start = lastParseIndex;
TableFilter filter = readSimpleTableFilter(0);
command.setTableFilter(filter);
parseUpdateSetClause(command, filter);
if (readIf("WHERE")) {
Expression condition = readExpression();
command.setCondition(condition);
}
if (readIf("ORDER")) {
// for MySQL compatibility
// (this syntax is supported, but ignored)
read("BY");
parseSimpleOrderList();
}
if (readIf("LIMIT")) {
Expression limit = readTerm().optimize(session);
command.setLimit(limit);
}
setSQL(command, "UPDATE", start);
parseUpdateSetClause(command, filter, start);
return command;
}
private void parseUpdateSetClause(Update command, TableFilter filter) {
private void parseUpdateSetClause(Update command, TableFilter filter, int start) {
read("SET");
if (readIf("(")) {
ArrayList<Column> columns = New.arrayList();
......@@ -802,6 +786,21 @@ public class Parser {
command.setAssignment(column, expression);
} while (readIf(","));
}
if (readIf("WHERE")) {
Expression condition = readExpression();
command.setCondition(condition);
}
if (readIf("ORDER")) {
// for MySQL compatibility
// (this syntax is supported, but ignored)
read("BY");
parseSimpleOrderList();
}
if (readIf("LIMIT")) {
Expression limit = readTerm().optimize(session);
command.setLimit(limit);
}
setSQL(command, "UPDATE", start);
}
private TableFilter readSimpleTableFilter(int orderInFrom) {
......@@ -1130,8 +1129,17 @@ public class Parser {
read(")");
}
command.setQueryAlias(readFromAlias(null, Arrays.asList("ON")));
Table tableOrView = command.getQuery().getTables().toArray(new Table[]{null})[0];
TableFilter sourceTableFilter = new TableFilter(session, tableOrView, command.getQueryAlias(), rightsChecked,
String[] querySQLOutput = new String[]{null};
List<Column> columnTemplateList = createQueryColumnTemplateList(null, command.getQuery(), querySQLOutput);
System.out.println("pre:alias="+command.getQueryAlias()+",sql="+querySQLOutput[0]+",ctlist="+columnTemplateList);
TableView temporarySourceTableView = createTemporarySessionView(command.getQueryAlias(), querySQLOutput[0], columnTemplateList, false);
command.setTemporaryTableView(temporarySourceTableView);
//Table tableOrView = command.getQuery().getTables().toArray(new Table[]{null})[0];
System.out.println("sourceTableFilter with tableOrView="+temporarySourceTableView);
System.out.println("sourceTableFilter rightsChecked="+rightsChecked);
TableFilter sourceTableFilter = new TableFilter(session, temporarySourceTableView, command.getQueryAlias(), rightsChecked,
(Select) command.getQuery(), 0, null);
command.setSourceTableFilter(sourceTableFilter);
}
......@@ -1154,23 +1162,25 @@ public class Parser {
read("ON");
read("(");
Expression condition = readExpression();
command.addCondition(condition);
command.addOnCondition(condition);
read(")");
if(readIf("WHEN")&&readIf("MATCHED")&&readIf("THEN")){
int startMatched = lastParseIndex;
if (readIf("UPDATE")){
Update updateCommand = new Update(session);
//currentPrepared = updateCommand;
TableFilter filter = command.getTargetTableFilter();
updateCommand.setTableFilter(filter);
parseUpdateSetClause(updateCommand, filter);
parseUpdateSetClause(updateCommand, filter,startMatched);
command.setUpdateCommand(updateCommand);
}
startMatched = lastParseIndex;
if (readIf("DELETE")){
Delete deleteCommand = new Delete(session);
TableFilter filter = command.getTargetTableFilter();
deleteCommand.setTableFilter(filter);
parseDeleteGivenTable(deleteCommand,null,lastParseIndex);
parseDeleteGivenTable(deleteCommand,null,startMatched);
command.setDeleteCommand(deleteCommand);
}
}
......@@ -1189,11 +1199,7 @@ public class Parser {
System.out.println("schemaName="+schemaName);
throw DbException.getUnsupportedException("unexpected null schema");
}
String[] querySQLOutput = new String[]{null};
List<Column> columnTemplateList = createQueryColumnTemplateList(null, command.getQuery(), querySQLOutput);
System.out.println("pre:alias="+command.getQueryAlias()+",sql="+querySQLOutput[0]+",cte="+columnTemplateList);
TableView temporarySourceTableView = createTemporarySessionView(command.getQueryAlias(), querySQLOutput[0], columnTemplateList, false);
command.setTemporaryTableView(temporarySourceTableView);
}
setSQL(command, "MERGE", start);
return command;
......
......@@ -30,19 +30,20 @@ import org.h2.value.ValueNull;
public class Delete extends Prepared {
private Expression condition;
private TableFilter tableFilter;
private TableFilter targetTableFilter;
/**
* The limit expression as specified in the LIMIT or TOP clause.
*/
private Expression limitExpr;
private TableFilter sourceTableFilter;
public Delete(Session session) {
super(session);
}
public void setTableFilter(TableFilter tableFilter) {
this.tableFilter = tableFilter;
this.targetTableFilter = tableFilter;
}
public void setCondition(Expression condition) {
......@@ -51,9 +52,9 @@ public class Delete extends Prepared {
@Override
public int update() {
tableFilter.startQuery(session);
tableFilter.reset();
Table table = tableFilter.getTable();
targetTableFilter.startQuery(session);
targetTableFilter.reset();
Table table = targetTableFilter.getTable();
session.getUser().checkRight(table, Right.DELETE);
table.fire(session, Trigger.DELETE, true);
table.lock(session, true, false);
......@@ -68,11 +69,11 @@ public class Delete extends Prepared {
try {
setCurrentRowNumber(0);
int count = 0;
while (limitRows != 0 && tableFilter.next()) {
while (limitRows != 0 && targetTableFilter.next()) {
setCurrentRowNumber(rows.size() + 1);
if (condition == null || Boolean.TRUE.equals(
condition.getBooleanValue(session))) {
Row row = tableFilter.get();
Row row = targetTableFilter.get();
boolean done = false;
if (table.fireRow()) {
done = table.fireBeforeRow(session, row, null);
......@@ -112,7 +113,7 @@ public class Delete extends Prepared {
public String getPlanSQL() {
StringBuilder buff = new StringBuilder();
buff.append("DELETE ");
buff.append("FROM ").append(tableFilter.getPlanSQL(false));
buff.append("FROM ").append(targetTableFilter.getPlanSQL(false));
if (condition != null) {
buff.append("\nWHERE ").append(StringUtils.unEnclose(
condition.getSQL()));
......@@ -127,15 +128,18 @@ public class Delete extends Prepared {
@Override
public void prepare() {
if (condition != null) {
condition.mapColumns(tableFilter, 0);
condition.mapColumns(targetTableFilter, 0);
if(sourceTableFilter!=null){
condition.mapColumns(sourceTableFilter, 0);
}
condition = condition.optimize(session);
condition.createIndexConditions(session, tableFilter);
condition.createIndexConditions(session, targetTableFilter);
}
TableFilter[] filters = new TableFilter[] { tableFilter };
PlanItem item = tableFilter.getBestPlanItem(session, filters, 0,
TableFilter[] filters = new TableFilter[] { targetTableFilter, sourceTableFilter };
PlanItem item = targetTableFilter.getBestPlanItem(session, filters, 0,
ExpressionVisitor.allColumnsForTableFilters(filters));
tableFilter.setPlanItem(item);
tableFilter.prepare();
targetTableFilter.setPlanItem(item);
targetTableFilter.prepare();
}
@Override
......@@ -162,4 +166,16 @@ public class Delete extends Prepared {
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;
import org.h2.result.Row;
import org.h2.table.Column;
import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.util.New;
import org.h2.util.StatementBuilder;
import org.h2.value.Value;
......@@ -46,6 +47,7 @@ public class Insert extends Prepared implements ResultTarget {
private boolean sortedInsertMode;
private int rowNumber;
private boolean insertFromSelect;
private TableFilter sourceTableFilter;
/**
* For MySQL-style INSERT ... ON DUPLICATE KEY UPDATE ....
......@@ -267,6 +269,9 @@ public class Insert extends Prepared implements ResultTarget {
for (int i = 0, len = expr.length; i < len; i++) {
Expression e = expr[i];
if (e != null) {
if(sourceTableFilter!=null){
e.mapColumns(sourceTableFilter, 0);
}
e = e.optimize(session);
if (e instanceof Parameter) {
Parameter p = (Parameter) e;
......@@ -395,4 +400,8 @@ public class Insert extends Prepared implements ResultTarget {
return condition;
}
public void setSourceTableFilter(TableFilter sourceTableFilter) {
this.sourceTableFilter = sourceTableFilter;
}
}
......@@ -6,6 +6,7 @@
package org.h2.command.dml;
import java.util.ArrayList;
import java.util.Arrays;
import org.h2.api.ErrorCode;
import org.h2.api.Trigger;
import org.h2.command.Prepared;
......@@ -19,6 +20,7 @@ import org.h2.index.Index;
import org.h2.message.DbException;
import org.h2.result.ResultInterface;
import org.h2.result.Row;
import org.h2.result.RowImpl;
import org.h2.table.Column;
import org.h2.table.PlanItem;
import org.h2.table.TableFilter;
......@@ -33,7 +35,7 @@ import org.h2.value.Value;
public class MergeUsing extends Merge {
private TableFilter sourceTableFilter;
private ArrayList<Expression> conditions = new ArrayList<Expression>();
private ArrayList<Expression> onConditions = new ArrayList<Expression>();
private Update updateCommand;
private Delete deleteCommand;
private Insert insertCommand;
......@@ -52,7 +54,7 @@ public class MergeUsing extends Merge {
@Override
public int update() {
System.out.println("update");
System.out.println("update using:"+temporarySourceTableView);
if(targetTableFilter!=null){
targetTableFilter.startQuery(session);
......@@ -75,20 +77,25 @@ public class MergeUsing extends Merge {
targetTable.lock(session, true, false);
while (rows.next()) {
count++;
Value[] r = rows.currentRow();
Row newRow = targetTable.getTemplateRow();
Value[] sourceRowValues = rows.currentRow();
Row sourceRow = new RowImpl(sourceRowValues,0);
System.out.println(("currentRowValues="+Arrays.toString(sourceRowValues)));
Row newTargetRow = targetTable.getTemplateRow();
setCurrentRowNumber(count);
System.out.println("columns="+Arrays.toString(columns));
// computer the new target row columns values
for (int j = 0; j < columns.length; j++) {
Column c = columns[j];
int index = c.getColumnId();
try {
Value v = c.convert(r[j]);
newRow.setValue(index, v);
Value v = c.convert(sourceRowValues[j]);
newTargetRow.setValue(index, v);
} catch (DbException ex) {
throw setRow(ex, count, getSQL(r));
throw setRow(ex, count, getSQL(sourceRowValues));
}
}
merge(newRow);
merge(sourceRow, sourceRowValues,newTargetRow);
}
rows.close();
targetTable.fire(session, evaluateTriggerMasks(), false);
......@@ -122,45 +129,36 @@ public class MergeUsing extends Merge {
}
}
@Override
protected void merge(Row row) {
ArrayList<Parameter> k = update.getParameters();
for (int i = 0; i < columns.length; i++) {
Column col = columns[i];
Value v = row.getValue(col.getColumnId());
Parameter p = k.get(i);
p.setValue(v);
}
for (int i = 0; i < keys.length; i++) {
Column col = keys[i];
Value v = row.getValue(col.getColumnId());
if (v == null) {
throw DbException.get(ErrorCode.COLUMN_CONTAINS_NULL_VALUES_1, col.getSQL());
}
Parameter p = k.get(columns.length + i);
p.setValue(v);
}
protected void merge(Row sourceRow, Value[] sourceRowValues, Row newTargetRow) {
configPreparedParameters(newTargetRow, update);
// put the column values into the table filter
sourceTableFilter.set(sourceRow);
// try and update
int count = 0;
if(updateCommand!=null){
count+=updateCommand.update();
System.out.println("onConditions="+onConditions.toString());
System.out.println("updatePlanSQL="+updateCommand.getPlanSQL());
count += updateCommand.update();
System.out.println("update.count="+count);
}
if(deleteCommand!=null && count==0){
count+=deleteCommand.update();
count += deleteCommand.update();
System.out.println("delete.count="+count);
}
// if either updates do nothing, try an insert
if (count == 0) {
try {
targetTable.validateConvertUpdateSequence(session, row);
boolean done = targetTable.fireBeforeRow(session, null, row);
targetTable.validateConvertUpdateSequence(session, newTargetRow);
boolean done = targetTable.fireBeforeRow(session, null, newTargetRow);
if (!done) {
targetTable.lock(session, true, false);
//targetTable.addRow(session, row);
addRowByInsert(session,row);
session.log(targetTable, UndoLogRecord.INSERT, row);
targetTable.fireAfterRow(session, null, row, false);
addRowByInsert(session,newTargetRow);
session.log(targetTable, UndoLogRecord.INSERT, newTargetRow);
targetTable.fireAfterRow(session, null, newTargetRow, false);
}
} catch (DbException e) {
if (e.getErrorCode() == ErrorCode.DUPLICATE_KEY_1) {
......@@ -190,6 +188,29 @@ public class MergeUsing extends Merge {
}
}
private void configPreparedParameters(Row newTargetRow, Prepared updatePrepared) {
ArrayList<Parameter> k = updatePrepared.getParameters();
// set each parameter in the updatePrepared with the real value from the source column
// 0 to columns.length-1
for (int i = 0; i < columns.length; i++) {
Column col = columns[i];
Value v = newTargetRow.getValue(col.getColumnId());
Parameter p = k.get(i);
p.setValue(v);
}
// columns.length to columns.length+keys.length-1
for (int i = 0; i < keys.length; i++) {
Column col = keys[i];
Value v = newTargetRow.getValue(col.getColumnId());
if (v == null) {
throw DbException.get(ErrorCode.COLUMN_CONTAINS_NULL_VALUES_1, col.getSQL());
}
Parameter p = k.get(columns.length + i);
p.setValue(v);
}
}
private void addRowByInsert(Session session, Row row) {
System.out.println("addRowByInsert=(hashcode)"+row.hashCode());
targetTable.addRow(session, row);
......@@ -284,18 +305,21 @@ public class MergeUsing extends Merge {
public void prepare() {
System.out.println("prepare:targetTableFilterAlias="+targetTableFilter.getTableAlias());
System.out.println("prepare:sourceTableFilterAlias="+sourceTableFilter.getTableAlias());
System.out.println("prepare:conditions="+conditions);
System.out.println("prepare:onConditions="+onConditions);
TableFilter[] filters = new TableFilter[] { sourceTableFilter, targetTableFilter };
for(Expression condition: conditions) {
for(Expression condition: onConditions) {
System.out.println("condition="+condition+":op="+condition.getClass().getSimpleName());
filters[0].addJoin(filters[1], false, true, condition);
condition.mapColumns(sourceTableFilter, 0);
//condition.mapColumns(targetTableFilter, 0);
condition.addFilterConditions(sourceTableFilter, true);
condition.addFilterConditions(targetTableFilter, true);
condition.mapColumns(sourceTableFilter, 2);
condition.mapColumns(targetTableFilter, 1);
condition = condition.optimize(session);
condition.createIndexConditions(session, sourceTableFilter);
//condition.createIndexConditions(session, targetTableFilter);
//optional
condition.createIndexConditions(session, targetTableFilter);
}
if (columns == null) {
......@@ -336,12 +360,15 @@ public class MergeUsing extends Merge {
// Not sure how these sub-prepares will work...
if(updateCommand!=null){
updateCommand.setSourceTableFilter(sourceTableFilter);
updateCommand.prepare();
}
if(deleteCommand!=null){
deleteCommand.setSourceTableFilter(sourceTableFilter);
deleteCommand.prepare();
}
if(insertCommand!=null){
insertCommand.setSourceTableFilter(sourceTableFilter);
insertCommand.prepare();
}
......@@ -373,8 +400,8 @@ public class MergeUsing extends Merge {
this.sourceTableFilter = sourceTableFilter;
}
public void addCondition(Expression condition) {
this.conditions .add(condition);
public void addOnCondition(Expression condition) {
this.onConditions .add(condition);
}
public Prepared getUpdateCommand() {
......
......@@ -38,7 +38,8 @@ import org.h2.value.ValueNull;
public class Update extends Prepared {
private Expression condition;
private TableFilter tableFilter;
private TableFilter targetTableFilter;// target of update
private TableFilter sourceTableFilter;// optional source query
/** The limit expression as specified in the LIMIT clause. */
private Expression limitExpr;
......@@ -51,7 +52,7 @@ public class Update extends Prepared {
}
public void setTableFilter(TableFilter tableFilter) {
this.tableFilter = tableFilter;
this.targetTableFilter = tableFilter;
}
public void setCondition(Expression condition) {
......@@ -79,11 +80,11 @@ public class Update extends Prepared {
@Override
public int update() {
tableFilter.startQuery(session);
tableFilter.reset();
targetTableFilter.startQuery(session);
targetTableFilter.reset();
RowList rows = new RowList(session);
try {
Table table = tableFilter.getTable();
Table table = targetTableFilter.getTable();
session.getUser().checkRight(table, Right.UPDATE);
table.fire(session, Trigger.UPDATE, true);
table.lock(session, true, false);
......@@ -99,14 +100,14 @@ public class Update extends Prepared {
limitRows = v.getInt();
}
}
while (tableFilter.next()) {
while (targetTableFilter.next()) {
setCurrentRowNumber(count+1);
if (limitRows >= 0 && count >= limitRows) {
break;
}
if (condition == null ||
Boolean.TRUE.equals(condition.getBooleanValue(session))) {
Row oldRow = tableFilter.get();
Row oldRow = targetTableFilter.get();
Row newRow = table.getTemplateRow();
for (int i = 0; i < columnCount; i++) {
Expression newExpr = expressionMap.get(columns[i]);
......@@ -161,7 +162,7 @@ public class Update extends Prepared {
@Override
public String getPlanSQL() {
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++) {
Column c = columns.get(i);
Expression e = expressionMap.get(c);
......@@ -181,21 +182,24 @@ public class Update extends Prepared {
@Override
public void prepare() {
if (condition != null) {
condition.mapColumns(tableFilter, 0);
condition.mapColumns(targetTableFilter, 0);
condition = condition.optimize(session);
condition.createIndexConditions(session, tableFilter);
condition.createIndexConditions(session, targetTableFilter);
}
for (int i = 0, size = columns.size(); i < size; i++) {
Column c = columns.get(i);
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));
}
TableFilter[] filters = new TableFilter[] { tableFilter };
PlanItem item = tableFilter.getBestPlanItem(session, filters, 0,
TableFilter[] filters = new TableFilter[] { targetTableFilter };
PlanItem item = targetTableFilter.getBestPlanItem(session, filters, 0,
ExpressionVisitor.allColumnsForTableFilters(filters));
tableFilter.setPlanItem(item);
tableFilter.prepare();
targetTableFilter.setPlanItem(item);
targetTableFilter.prepare();
}
@Override
......@@ -222,4 +226,12 @@ public class Update extends Prepared {
return true;
}
public TableFilter getSourceTableFilter() {
return sourceTableFilter;
}
public void setSourceTableFilter(TableFilter sourceTableFilter) {
this.sourceTableFilter = sourceTableFilter;
}
}
......@@ -492,8 +492,10 @@ public class Comparison extends Condition {
@Override
public void mapColumns(ColumnResolver resolver, int level) {
System.out.println("Checking left:"+left+" against "+resolver);
left.mapColumns(resolver, level);
if (right != null) {
System.out.println("Checking right:"+right+" against "+resolver);
right.mapColumns(resolver, level);
}
}
......
......@@ -117,9 +117,11 @@ public class ExpressionColumn extends Expression {
queryLevel = level;
column = col;
this.columnResolver = resolver;
System.out.println("mapColumn: Setting resolver:"+col+"@"+System.identityHashCode(col)+" by resolver "+resolver+"-"+resolver.getClass());
} else if (queryLevel == level && this.columnResolver != resolver) {
if (resolver instanceof SelectListColumnResolver) {
// ignore - already mapped, that's ok
System.out.println("mapColumn: Already mapped:"+col+"@"+System.identityHashCode(col)+" by resolver "+resolver+"-"+resolver.getClass());
} else {
throw DbException.get(ErrorCode.AMBIGUOUS_COLUMN_NAME_1, columnName);
}
......
......@@ -42,18 +42,18 @@ public class TestMergeUsing extends TestBase {
stat = conn.createStatement();
stat.execute("CREATE TABLE PARENT(ID INT, NAME VARCHAR, PRIMARY KEY(ID) );");
prep = conn.prepareStatement("MERGE INTO PARENT AS P USING (SELECT 1 AS ID, 'Marcy' AS NAME) AS S ON (P.ID = S.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)");
prep = conn.prepareStatement("MERGE INTO PARENT AS P USING (SELECT 1 AS ID, 'Marcy' AS NAME) AS S ON (P.ID = S.ID AND 1=1 AND S.ID = P.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)");
rowCount = prep.executeUpdate();
assertEquals(1,rowCount);
rs = stat.executeQuery("SELECT ID, X,Y FROM T1");
rs = stat.executeQuery("SELECT ID, NAME FROM PARENT");
for (int n : new int[] { 1 }) {
assertTrue(rs.next());
assertTrue(rs.getInt(1)!=0);
assertEquals(n, rs.getInt(2));
assertEquals("X1", rs.getString(3));
assertEquals(1,rs.getInt(1));
assertEquals("Marcy", rs.getString(2));
System.out.println("id="+rs.getInt(1)+",name="+rs.getString(2));
}
conn.close();
deleteDb("mergeUsingQueries");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论