提交 9f7ef4b1 authored 作者: XEHA6284's avatar XEHA6284

Add support for INSERT IGNORE from SELECT in MySQL Mode

上级 c433682f
/* /*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0, * Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html). * and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group * Initial Developer: H2 Group
*/ */
package org.h2.command.dml; package org.h2.command.dml;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
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;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.command.Prepared; import org.h2.command.Prepared;
import org.h2.engine.GeneratedKeys; import org.h2.engine.GeneratedKeys;
import org.h2.engine.Right; import org.h2.engine.Right;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.engine.UndoLogRecord; import org.h2.engine.UndoLogRecord;
import org.h2.expression.Comparison; import org.h2.expression.Comparison;
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.Parameter; import org.h2.expression.Parameter;
import org.h2.expression.SequenceValue; import org.h2.expression.SequenceValue;
import org.h2.index.Index; import org.h2.expression.ValueExpression;
import org.h2.index.PageDataIndex; import org.h2.index.Index;
import org.h2.message.DbException; import org.h2.index.PageDataIndex;
import org.h2.mvstore.db.MVPrimaryIndex; import org.h2.message.DbException;
import org.h2.result.ResultInterface; import org.h2.mvstore.db.MVPrimaryIndex;
import org.h2.result.ResultTarget; import org.h2.result.ResultInterface;
import org.h2.result.Row; import org.h2.result.ResultTarget;
import org.h2.table.Column; import org.h2.result.Row;
import org.h2.table.Table; import org.h2.table.Column;
import org.h2.table.TableFilter; import org.h2.table.Table;
import org.h2.util.StatementBuilder; import org.h2.table.TableFilter;
import org.h2.util.Utils; import org.h2.util.StatementBuilder;
import org.h2.value.Value; import org.h2.util.Utils;
import org.h2.value.ValueNull; import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* This class represents the statement /**
* INSERT * This class represents the statement
*/ * INSERT
public class Insert extends Prepared implements ResultTarget { */
public class Insert extends Prepared implements ResultTarget {
private Table table;
private Column[] columns; private Table table;
private final ArrayList<Expression[]> list = Utils.newSmallArrayList(); private Column[] columns;
private Query query; private final ArrayList<Expression[]> list = Utils.newSmallArrayList();
private boolean sortedInsertMode; private Query query;
private int rowNumber; private boolean sortedInsertMode;
private boolean insertFromSelect; private int rowNumber;
/** private boolean insertFromSelect;
* This table filter is for MERGE..USING support - not used in stand-alone DML /**
*/ * This table filter is for MERGE..USING support - not used in stand-alone DML
private TableFilter sourceTableFilter; */
private TableFilter sourceTableFilter;
/**
* For MySQL-style INSERT ... ON DUPLICATE KEY UPDATE .... /**
*/ * For MySQL-style INSERT ... ON DUPLICATE KEY UPDATE ....
private HashMap<Column, Expression> duplicateKeyAssignmentMap; */
private HashMap<Column, Expression> duplicateKeyAssignmentMap;
/**
* For MySQL-style INSERT IGNORE /**
*/ * For MySQL-style INSERT IGNORE
private boolean ignore; */
private boolean ignore;
public Insert(Session session) {
super(session); public Insert(Session session) {
} super(session);
}
@Override
public void setCommand(Command command) { @Override
super.setCommand(command); public void setCommand(Command command) {
if (query != null) { super.setCommand(command);
query.setCommand(command); if (query != null) {
} query.setCommand(command);
} }
}
public void setTable(Table table) {
this.table = table; public void setTable(Table table) {
} this.table = table;
}
public void setColumns(Column[] columns) {
this.columns = columns; public void setColumns(Column[] columns) {
} this.columns = columns;
}
/**
* Sets MySQL-style INSERT IGNORE mode /**
* @param ignore ignore errors * Sets MySQL-style INSERT IGNORE mode
*/ * @param ignore ignore errors
public void setIgnore(boolean ignore) { */
this.ignore = ignore; public void setIgnore(boolean ignore) {
} this.ignore = ignore;
}
public void setQuery(Query query) {
this.query = query; public void setQuery(Query query) {
} this.query = query;
}
/**
* Keep a collection of the columns to pass to update if a duplicate key /**
* happens, for MySQL-style INSERT ... ON DUPLICATE KEY UPDATE .... * Keep a collection of the columns to pass to update if a duplicate key
* * happens, for MySQL-style INSERT ... ON DUPLICATE KEY UPDATE ....
* @param column the column *
* @param expression the expression * @param column the column
*/ * @param expression the expression
public void addAssignmentForDuplicate(Column column, Expression expression) { */
if (duplicateKeyAssignmentMap == null) { public void addAssignmentForDuplicate(Column column, Expression expression) {
duplicateKeyAssignmentMap = new HashMap<>(); if (duplicateKeyAssignmentMap == null) {
} duplicateKeyAssignmentMap = new HashMap<>();
if (duplicateKeyAssignmentMap.containsKey(column)) { }
throw DbException.get(ErrorCode.DUPLICATE_COLUMN_NAME_1, if (duplicateKeyAssignmentMap.containsKey(column)) {
column.getName()); throw DbException.get(ErrorCode.DUPLICATE_COLUMN_NAME_1,
} column.getName());
duplicateKeyAssignmentMap.put(column, expression); }
} duplicateKeyAssignmentMap.put(column, expression);
}
/**
* Add a row to this merge statement. /**
* * Add a row to this merge statement.
* @param expr the list of values *
*/ * @param expr the list of values
public void addRow(Expression[] expr) { */
list.add(expr); public void addRow(Expression[] expr) {
} list.add(expr);
}
@Override
public int update() { @Override
Index index = null; public int update() {
if (sortedInsertMode) { Index index = null;
index = table.getScanIndex(session); if (sortedInsertMode) {
index.setSortedInsertMode(true); index = table.getScanIndex(session);
} index.setSortedInsertMode(true);
try { }
return insertRows(); try {
} finally { return insertRows();
if (index != null) { } finally {
index.setSortedInsertMode(false); if (index != null) {
} index.setSortedInsertMode(false);
} }
} }
}
private int insertRows() {
session.getUser().checkRight(table, Right.INSERT); private int insertRows() {
setCurrentRowNumber(0); session.getUser().checkRight(table, Right.INSERT);
table.fire(session, Trigger.INSERT, true); setCurrentRowNumber(0);
rowNumber = 0; table.fire(session, Trigger.INSERT, true);
GeneratedKeys generatedKeys = session.getGeneratedKeys(); rowNumber = 0;
generatedKeys.initialize(table); GeneratedKeys generatedKeys = session.getGeneratedKeys();
int listSize = list.size(); generatedKeys.initialize(table);
if (listSize > 0) { int listSize = list.size();
int columnLen = columns.length; if (listSize > 0) {
for (int x = 0; x < listSize; x++) { int columnLen = columns.length;
session.startStatementWithinTransaction(); for (int x = 0; x < listSize; x++) {
generatedKeys.nextRow(); session.startStatementWithinTransaction();
Row newRow = table.getTemplateRow(); generatedKeys.nextRow();
Expression[] expr = list.get(x); Row newRow = table.getTemplateRow();
setCurrentRowNumber(x + 1); Expression[] expr = list.get(x);
for (int i = 0; i < columnLen; i++) { setCurrentRowNumber(x + 1);
Column c = columns[i]; for (int i = 0; i < columnLen; i++) {
int index = c.getColumnId(); Column c = columns[i];
Expression e = expr[i]; int index = c.getColumnId();
if (e != null) { Expression e = expr[i];
// e can be null (DEFAULT) if (e != null) {
e = e.optimize(session); // e can be null (DEFAULT)
try { e = e.optimize(session);
Value v = c.convert(e.getValue(session), session.getDatabase().getMode()); try {
newRow.setValue(index, v); Value v = c.convert(e.getValue(session), session.getDatabase().getMode());
if (e instanceof SequenceValue) { newRow.setValue(index, v);
generatedKeys.add(c); if (e instanceof SequenceValue) {
} generatedKeys.add(c);
} catch (DbException ex) { }
throw setRow(ex, x, getSQL(expr)); } catch (DbException ex) {
} throw setRow(ex, x, getSQL(expr));
} }
} }
rowNumber++; }
table.validateConvertUpdateSequence(session, newRow); rowNumber++;
boolean done = table.fireBeforeRow(session, null, newRow); table.validateConvertUpdateSequence(session, newRow);
if (!done) { boolean done = table.fireBeforeRow(session, null, newRow);
table.lock(session, true, false); if (!done) {
try { table.lock(session, true, false);
table.addRow(session, newRow); try {
} catch (DbException de) { table.addRow(session, newRow);
if (handleOnDuplicate(de)) { } catch (DbException de) {
// MySQL returns 2 for updated row if (handleOnDuplicate(de)) {
// TODO: detect no-op change // MySQL returns 2 for updated row
rowNumber++; // TODO: detect no-op change
} else { rowNumber++;
// INSERT IGNORE case } else {
rowNumber--; // INSERT IGNORE case
} rowNumber--;
continue; }
} continue;
generatedKeys.confirmRow(newRow); }
session.log(table, UndoLogRecord.INSERT, newRow); generatedKeys.confirmRow(newRow);
table.fireAfterRow(session, null, newRow, false); session.log(table, UndoLogRecord.INSERT, newRow);
} table.fireAfterRow(session, null, newRow, false);
} }
} else { }
table.lock(session, true, false); } else {
if (insertFromSelect) { table.lock(session, true, false);
query.query(0, this); if (insertFromSelect) {
} else { query.query(0, this);
ResultInterface rows = query.query(0); } else {
while (rows.next()) { ResultInterface rows = query.query(0);
generatedKeys.nextRow(); while (rows.next()) {
Value[] r = rows.currentRow(); generatedKeys.nextRow();
Row newRow = addRowImpl(r); Value[] r = rows.currentRow();
if (newRow != null) { try {
generatedKeys.confirmRow(newRow); Row newRow = addRowImpl(r);
} if (newRow != null) {
} generatedKeys.confirmRow(newRow);
rows.close(); }
} } catch (DbException de) {
} if (handleOnDuplicate(de)) {
table.fire(session, Trigger.INSERT, false); // MySQL returns 2 for updated row
return rowNumber; // TODO: detect no-op change
} rowNumber++;
} else {
@Override // INSERT IGNORE case
public void addRow(Value[] values) { rowNumber--;
addRowImpl(values); }
} }
}
private Row addRowImpl(Value[] values) { rows.close();
Row newRow = table.getTemplateRow(); }
setCurrentRowNumber(++rowNumber); }
for (int j = 0, len = columns.length; j < len; j++) { table.fire(session, Trigger.INSERT, false);
Column c = columns[j]; return rowNumber;
int index = c.getColumnId(); }
try {
Value v = c.convert(values[j], session.getDatabase().getMode()); @Override
newRow.setValue(index, v); public void addRow(Value[] values) {
} catch (DbException ex) { addRowImpl(values);
throw setRow(ex, rowNumber, getSQL(values)); }
}
} private Row addRowImpl(Value[] values) {
table.validateConvertUpdateSequence(session, newRow); Row newRow = table.getTemplateRow();
boolean done = table.fireBeforeRow(session, null, newRow); setCurrentRowNumber(++rowNumber);
if (!done) { Expression[] exp = new Expression[columns.length];
table.addRow(session, newRow); for (int j = 0, len = columns.length; j < len; j++) {
session.log(table, UndoLogRecord.INSERT, newRow); Column c = columns[j];
table.fireAfterRow(session, null, newRow, false); int index = c.getColumnId();
return newRow; try {
} Value v = c.convert(values[j], session.getDatabase().getMode());
return null; newRow.setValue(index, v);
} exp[j] = ValueExpression.get(v);
} catch (DbException ex) {
@Override throw setRow(ex, rowNumber, getSQL(values));
public int getRowCount() { }
return rowNumber; }
} table.validateConvertUpdateSequence(session, newRow);
boolean done = table.fireBeforeRow(session, null, newRow);
@Override if (!done) {
public String getPlanSQL() { addRow(exp);
StatementBuilder buff = new StatementBuilder("INSERT INTO "); table.addRow(session, newRow);
buff.append(table.getSQL()).append('('); session.log(table, UndoLogRecord.INSERT, newRow);
for (Column c : columns) { table.fireAfterRow(session, null, newRow, false);
buff.appendExceptFirst(", "); return newRow;
buff.append(c.getSQL()); }
} return null;
buff.append(")\n"); }
if (insertFromSelect) {
buff.append("DIRECT "); @Override
} public int getRowCount() {
if (sortedInsertMode) { return rowNumber;
buff.append("SORTED "); }
}
if (!list.isEmpty()) { @Override
buff.append("VALUES "); public String getPlanSQL() {
int row = 0; StatementBuilder buff = new StatementBuilder("INSERT INTO ");
if (list.size() > 1) { buff.append(table.getSQL()).append('(');
buff.append('\n'); for (Column c : columns) {
} buff.appendExceptFirst(", ");
for (Expression[] expr : list) { buff.append(c.getSQL());
if (row++ > 0) { }
buff.append(",\n"); buff.append(")\n");
} if (insertFromSelect) {
buff.append('('); buff.append("DIRECT ");
buff.resetCount(); }
for (Expression e : expr) { if (sortedInsertMode) {
buff.appendExceptFirst(", "); buff.append("SORTED ");
if (e == null) { }
buff.append("DEFAULT"); if (!list.isEmpty()) {
} else { buff.append("VALUES ");
buff.append(e.getSQL()); int row = 0;
} if (list.size() > 1) {
} buff.append('\n');
buff.append(')'); }
} for (Expression[] expr : list) {
} else { if (row++ > 0) {
buff.append(query.getPlanSQL()); buff.append(",\n");
} }
return buff.toString(); buff.append('(');
} buff.resetCount();
for (Expression e : expr) {
@Override buff.appendExceptFirst(", ");
public void prepare() { if (e == null) {
if (columns == null) { buff.append("DEFAULT");
if (!list.isEmpty() && list.get(0).length == 0) { } else {
// special case where table is used as a sequence buff.append(e.getSQL());
columns = new Column[0]; }
} else { }
columns = table.getColumns(); buff.append(')');
} }
} } else {
if (!list.isEmpty()) { buff.append(query.getPlanSQL());
for (Expression[] expr : list) { }
if (expr.length != columns.length) { return buff.toString();
throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH); }
}
for (int i = 0, len = expr.length; i < len; i++) { @Override
Expression e = expr[i]; public void prepare() {
if (e != null) { if (columns == null) {
if(sourceTableFilter!=null){ if (!list.isEmpty() && list.get(0).length == 0) {
e.mapColumns(sourceTableFilter, 0); // special case where table is used as a sequence
} columns = new Column[0];
e = e.optimize(session); } else {
if (e instanceof Parameter) { columns = table.getColumns();
Parameter p = (Parameter) e; }
p.setColumn(columns[i]); }
} if (!list.isEmpty()) {
expr[i] = e; for (Expression[] expr : list) {
} if (expr.length != columns.length) {
} throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
} }
} else { for (int i = 0, len = expr.length; i < len; i++) {
query.prepare(); Expression e = expr[i];
if (query.getColumnCount() != columns.length) { if (e != null) {
throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH); if(sourceTableFilter!=null){
} e.mapColumns(sourceTableFilter, 0);
} }
} e = e.optimize(session);
if (e instanceof Parameter) {
@Override Parameter p = (Parameter) e;
public boolean isTransactional() { p.setColumn(columns[i]);
return true; }
} expr[i] = e;
}
@Override }
public ResultInterface queryMeta() { }
return null; } else {
} query.prepare();
if (query.getColumnCount() != columns.length) {
public void setSortedInsertMode(boolean sortedInsertMode) { throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
this.sortedInsertMode = sortedInsertMode; }
} }
}
@Override
public int getType() { @Override
return CommandInterface.INSERT; public boolean isTransactional() {
} return true;
}
public void setInsertFromSelect(boolean value) {
this.insertFromSelect = value; @Override
} public ResultInterface queryMeta() {
return null;
@Override }
public boolean isCacheable() {
return duplicateKeyAssignmentMap == null || public void setSortedInsertMode(boolean sortedInsertMode) {
duplicateKeyAssignmentMap.isEmpty(); this.sortedInsertMode = sortedInsertMode;
} }
/** @Override
* @param de duplicate key exception public int getType() {
* @return {@code true} if row was updated, {@code false} if row was ignored return CommandInterface.INSERT;
*/ }
private boolean handleOnDuplicate(DbException de) {
if (de.getErrorCode() != ErrorCode.DUPLICATE_KEY_1) { public void setInsertFromSelect(boolean value) {
throw de; this.insertFromSelect = value;
} }
if (duplicateKeyAssignmentMap == null ||
duplicateKeyAssignmentMap.isEmpty()) { @Override
if (ignore) { public boolean isCacheable() {
return false; return duplicateKeyAssignmentMap == null ||
} duplicateKeyAssignmentMap.isEmpty();
throw de; }
}
/**
ArrayList<String> variableNames = new ArrayList<>( * @param de duplicate key exception
duplicateKeyAssignmentMap.size()); * @return {@code true} if row was updated, {@code false} if row was ignored
Expression[] row = list.get(getCurrentRowNumber() - 1); */
for (int i = 0; i < columns.length; i++) { private boolean handleOnDuplicate(DbException de) {
String key = table.getSchema().getName() + "." + if (de.getErrorCode() != ErrorCode.DUPLICATE_KEY_1) {
table.getName() + "." + columns[i].getName(); throw de;
variableNames.add(key); }
session.setVariable(key, if (duplicateKeyAssignmentMap == null ||
row[i].getValue(session)); duplicateKeyAssignmentMap.isEmpty()) {
} if (ignore) {
return false;
StatementBuilder buff = new StatementBuilder("UPDATE "); }
buff.append(table.getSQL()).append(" SET "); throw de;
for (Column column : duplicateKeyAssignmentMap.keySet()) { }
buff.appendExceptFirst(", ");
Expression ex = duplicateKeyAssignmentMap.get(column); ArrayList<String> variableNames = new ArrayList<>(
buff.append(column.getSQL()).append("=").append(ex.getSQL()); duplicateKeyAssignmentMap.size());
} Expression[] row = list.get(getCurrentRowNumber() - 1);
buff.append(" WHERE "); for (int i = 0; i < columns.length; i++) {
Index foundIndex = (Index) de.getSource(); String key = table.getSchema().getName() + "." +
if (foundIndex == null) { table.getName() + "." + columns[i].getName();
throw DbException.getUnsupportedException( variableNames.add(key);
"Unable to apply ON DUPLICATE KEY UPDATE, no index found!"); session.setVariable(key,
} row[i].getValue(session));
buff.append(prepareUpdateCondition(foundIndex).getSQL()); }
String sql = buff.toString();
Update command = (Update) session.prepare(sql); StatementBuilder buff = new StatementBuilder("UPDATE ");
command.setUpdateToCurrentValuesReturnsZero(true); buff.append(table.getSQL()).append(" SET ");
for (Parameter param : command.getParameters()) { for (Column column : duplicateKeyAssignmentMap.keySet()) {
Parameter insertParam = parameters.get(param.getIndex()); buff.appendExceptFirst(", ");
param.setValue(insertParam.getValue(session)); Expression ex = duplicateKeyAssignmentMap.get(column);
} buff.append(column.getSQL()).append("=").append(ex.getSQL());
boolean result = command.update() > 0; }
for (String variableName : variableNames) { buff.append(" WHERE ");
session.setVariable(variableName, ValueNull.INSTANCE); Index foundIndex = (Index) de.getSource();
} if (foundIndex == null) {
return result; throw DbException.getUnsupportedException(
} "Unable to apply ON DUPLICATE KEY UPDATE, no index found!");
}
private Expression prepareUpdateCondition(Index foundIndex) { buff.append(prepareUpdateCondition(foundIndex).getSQL());
// MVPrimaryIndex is playing fast and loose with it's implementation of String sql = buff.toString();
// the Index interface. Update command = (Update) session.prepare(sql);
// It returns all of the columns in the table when we call command.setUpdateToCurrentValuesReturnsZero(true);
// getIndexColumns() or getColumns(). for (Parameter param : command.getParameters()) {
// Don't have time right now to fix that, so just special-case it. Parameter insertParam = parameters.get(param.getIndex());
// PageDataIndex has the same problem. param.setValue(insertParam.getValue(session));
final Column[] indexedColumns; }
if (foundIndex instanceof MVPrimaryIndex) { boolean result = command.update() > 0;
MVPrimaryIndex foundMV = (MVPrimaryIndex) foundIndex; for (String variableName : variableNames) {
indexedColumns = new Column[] { foundMV.getIndexColumns()[foundMV session.setVariable(variableName, ValueNull.INSTANCE);
.getMainIndexColumn()].column }; }
} else if (foundIndex instanceof PageDataIndex) { return result;
PageDataIndex foundPD = (PageDataIndex) foundIndex; }
int mainIndexColumn = foundPD.getMainIndexColumn();
indexedColumns = mainIndexColumn >= 0 private Expression prepareUpdateCondition(Index foundIndex) {
? new Column[] { foundPD.getIndexColumns()[mainIndexColumn].column } // MVPrimaryIndex is playing fast and loose with it's implementation of
: foundIndex.getColumns(); // the Index interface.
} else { // It returns all of the columns in the table when we call
indexedColumns = foundIndex.getColumns(); // getIndexColumns() or getColumns().
} // Don't have time right now to fix that, so just special-case it.
// PageDataIndex has the same problem.
Expression[] row = list.get(getCurrentRowNumber() - 1); final Column[] indexedColumns;
Expression condition = null; if (foundIndex instanceof MVPrimaryIndex) {
for (Column column : indexedColumns) { MVPrimaryIndex foundMV = (MVPrimaryIndex) foundIndex;
ExpressionColumn expr = new ExpressionColumn(session.getDatabase(), indexedColumns = new Column[] { foundMV.getIndexColumns()[foundMV
table.getSchema().getName(), table.getName(), .getMainIndexColumn()].column };
column.getName()); } else if (foundIndex instanceof PageDataIndex) {
for (int i = 0; i < columns.length; i++) { PageDataIndex foundPD = (PageDataIndex) foundIndex;
if (expr.getColumnName().equals(columns[i].getName())) { int mainIndexColumn = foundPD.getMainIndexColumn();
if (condition == null) { indexedColumns = mainIndexColumn >= 0
condition = new Comparison(session, Comparison.EQUAL, expr, row[i]); ? new Column[] { foundPD.getIndexColumns()[mainIndexColumn].column }
} else { : foundIndex.getColumns();
condition = new ConditionAndOr(ConditionAndOr.AND, condition, } else {
new Comparison(session, Comparison.EQUAL, expr, row[i])); indexedColumns = foundIndex.getColumns();
} }
break;
} Expression[] row = list.get(getCurrentRowNumber() - 1);
} Expression condition = null;
} for (Column column : indexedColumns) {
return condition; ExpressionColumn expr = new ExpressionColumn(session.getDatabase(),
} table.getSchema().getName(), table.getName(),
column.getName());
public void setSourceTableFilter(TableFilter sourceTableFilter) { for (int i = 0; i < columns.length; i++) {
this.sourceTableFilter = sourceTableFilter; if (expr.getColumnName().equals(columns[i].getName())) {
} if (condition == null) {
condition = new Comparison(session, Comparison.EQUAL, expr, row[i]);
} } else {
condition = new ConditionAndOr(ConditionAndOr.AND, condition,
new Comparison(session, Comparison.EQUAL, expr, row[i]));
}
break;
}
}
}
return condition;
}
public void setSourceTableFilter(TableFilter sourceTableFilter) {
this.sourceTableFilter = sourceTableFilter;
}
}
-- Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0, -- Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
-- and the EPL 1.0 (http://h2database.com/html/license.html). -- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group -- Initial Developer: H2 Group
-- --
SET MODE MySQL; SET MODE MySQL;
> ok > ok
CREATE TABLE TEST(ID BIGINT PRIMARY KEY, VALUE INT NOT NULL); CREATE TABLE TEST(ID BIGINT PRIMARY KEY, VALUE INT NOT NULL);
> ok > ok
INSERT INTO TEST VALUES (1, 10), (2, 20), (3, 30), (4, 40); INSERT INTO TEST VALUES (1, 10), (2, 20), (3, 30), (4, 40);
> update count: 4 > update count: 4
INSERT INTO TEST VALUES (3, 31), (5, 51); INSERT INTO TEST VALUES (3, 31), (5, 51);
> exception DUPLICATE_KEY_1 > exception DUPLICATE_KEY_1
SELECT * FROM TEST ORDER BY ID; SELECT * FROM TEST ORDER BY ID;
> ID VALUE > ID VALUE
> -- ----- > -- -----
> 1 10 > 1 10
> 2 20 > 2 20
> 3 30 > 3 30
> 4 40 > 4 40
> rows (ordered): 4 > rows (ordered): 4
INSERT IGNORE INTO TEST VALUES (3, 32), (5, 52); INSERT IGNORE INTO TEST VALUES (3, 32), (5, 52);
> update count: 1 > update count: 1
INSERT IGNORE INTO TEST VALUES (4, 43); INSERT IGNORE INTO TEST VALUES (4, 43);
> ok > ok
SELECT * FROM TEST ORDER BY ID; SELECT * FROM TEST ORDER BY ID;
> ID VALUE > ID VALUE
> -- ----- > -- -----
> 1 10 > 1 10
> 2 20 > 2 20
> 3 30 > 3 30
> 4 40 > 4 40
> 5 52 > 5 52
> rows (ordered): 5 > rows (ordered): 5
CREATE TABLE TESTREF(ID BIGINT PRIMARY KEY, VALUE INT NOT NULL);
> ok
INSERT INTO TESTREF VALUES (1, 11), (2, 21), (6, 61), (7, 71);
> update count: 4
INSERT INTO TEST (ID, VALUE) SELECT ID, VALUE FROM TESTREF;
> exception DUPLICATE_KEY_1
SELECT * FROM TEST ORDER BY ID;
> ID VALUE
> -- -----
> 1 10
> 2 20
> 3 30
> 4 40
> 5 52
> rows (ordered): 5
INSERT IGNORE INTO TEST (ID, VALUE) SELECT ID, VALUE FROM TESTREF;
> update count: 2
INSERT IGNORE INTO TEST (ID, VALUE) SELECT ID, VALUE FROM TESTREF;
> ok
SELECT * FROM TEST ORDER BY ID;
> ID VALUE
> -- -----
> 1 10
> 2 20
> 3 30
> 4 40
> 5 52
> 6 61
> 7 71
> rows (ordered): 7
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论