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

Pass the whole inserted row to GeneratedKeys to ensure that latest values will be returned

上级 a674f921
...@@ -166,7 +166,7 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -166,7 +166,7 @@ public class Insert extends Prepared implements ResultTarget {
Value v = c.convert(e.getValue(session), session.getDatabase().getMode()); Value v = c.convert(e.getValue(session), session.getDatabase().getMode());
newRow.setValue(index, v); newRow.setValue(index, v);
if (e instanceof SequenceValue) { if (e instanceof SequenceValue) {
generatedKeys.add(c, v); generatedKeys.add(c);
} }
} catch (DbException ex) { } catch (DbException ex) {
throw setRow(ex, x, getSQL(expr)); throw setRow(ex, x, getSQL(expr));
...@@ -187,7 +187,7 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -187,7 +187,7 @@ public class Insert extends Prepared implements ResultTarget {
continue; continue;
} }
} }
generatedKeys.confirmRow(); generatedKeys.confirmRow(newRow);
session.log(table, UndoLogRecord.INSERT, newRow); session.log(table, UndoLogRecord.INSERT, newRow);
table.fireAfterRow(session, null, newRow, false); table.fireAfterRow(session, null, newRow, false);
} }
......
...@@ -86,10 +86,10 @@ public class Merge extends Prepared { ...@@ -86,10 +86,10 @@ public class Merge extends Prepared {
session.getUser().checkRight(targetTable, Right.INSERT); session.getUser().checkRight(targetTable, Right.INSERT);
session.getUser().checkRight(targetTable, Right.UPDATE); session.getUser().checkRight(targetTable, Right.UPDATE);
setCurrentRowNumber(0); setCurrentRowNumber(0);
GeneratedKeys generatedKeys = session.getGeneratedKeys();
if (valuesExpressionList.size() > 0) { if (valuesExpressionList.size() > 0) {
// process values in list // process values in list
count = 0; count = 0;
GeneratedKeys generatedKeys = session.getGeneratedKeys();
generatedKeys.initialize(targetTable); generatedKeys.initialize(targetTable);
for (int x = 0, size = valuesExpressionList.size(); x < size; x++) { for (int x = 0, size = valuesExpressionList.size(); x < size; x++) {
setCurrentRowNumber(x + 1); setCurrentRowNumber(x + 1);
...@@ -106,7 +106,7 @@ public class Merge extends Prepared { ...@@ -106,7 +106,7 @@ public class Merge extends Prepared {
Value v = c.convert(e.getValue(session)); Value v = c.convert(e.getValue(session));
newRow.setValue(index, v); newRow.setValue(index, v);
if (e instanceof SequenceValue) { if (e instanceof SequenceValue) {
generatedKeys.add(c, v); generatedKeys.add(c);
} }
} catch (DbException ex) { } catch (DbException ex) {
throw setRow(ex, count, getSQL(expr)); throw setRow(ex, count, getSQL(expr));
...@@ -124,6 +124,7 @@ public class Merge extends Prepared { ...@@ -124,6 +124,7 @@ public class Merge extends Prepared {
targetTable.lock(session, true, false); targetTable.lock(session, true, false);
while (rows.next()) { while (rows.next()) {
count++; count++;
generatedKeys.nextRow();
Value[] r = rows.currentRow(); Value[] r = rows.currentRow();
Row newRow = targetTable.getTemplateRow(); Row newRow = targetTable.getTemplateRow();
setCurrentRowNumber(count); setCurrentRowNumber(count);
...@@ -179,7 +180,7 @@ public class Merge extends Prepared { ...@@ -179,7 +180,7 @@ public class Merge extends Prepared {
if (!done) { if (!done) {
targetTable.lock(session, true, false); targetTable.lock(session, true, false);
targetTable.addRow(session, row); targetTable.addRow(session, row);
session.getGeneratedKeys().confirmRow(); session.getGeneratedKeys().confirmRow(row);
session.log(targetTable, UndoLogRecord.INSERT, row); session.log(targetTable, UndoLogRecord.INSERT, row);
targetTable.fireAfterRow(session, null, row, false); targetTable.fireAfterRow(session, null, row, false);
} }
......
...@@ -11,67 +11,102 @@ import java.util.HashMap; ...@@ -11,67 +11,102 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.h2.message.DbException; import org.h2.message.DbException;
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.tools.SimpleResultSet; import org.h2.tools.SimpleResultSet;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.New; import org.h2.util.New;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.Value;
/** /**
* Generated keys. * Class for gathering and processing of generated keys.
*/ */
public final class GeneratedKeys { public final class GeneratedKeys {
/**
* Data for result set with generated keys.
*/
private final ArrayList<Map<Column, Object>> data = New.arrayList(); private final ArrayList<Map<Column, Object>> data = New.arrayList();
private final ArrayList<Object> row = New.arrayList(); /**
* Columns with generated keys in the current row.
*/
private final ArrayList<Column> row = New.arrayList();
private final ArrayList<Column> columns = New.arrayList(); /**
* All columns with generated keys.
*/
private final ArrayList<Column> allColumns = New.arrayList();
/**
* Request for keys gathering. {@code false} if generated keys are not needed,
* {@code true} if generated keys should be configured automatically,
* {@code int[]} to specify column indices to return generated keys from, or
* {@code String[]} to specify column names to return generated keys from.
*/
private Object generatedKeysRequest; private Object generatedKeysRequest;
/**
* Processed table.
*/
private Table table; private Table table;
public void add(Column column, Value value) { /**
* Remembers columns with generated keys.
*
* @param column
* table column
*/
public void add(Column column) {
if (Boolean.FALSE.equals(generatedKeysRequest)) { if (Boolean.FALSE.equals(generatedKeysRequest)) {
return; return;
} }
row.add(column); row.add(column);
row.add(value.getObject());
} }
/**
* Clears all information from previous runs and sets a new request for
* gathering of generated keys.
*
* @param generatedKeysRequest
* {@code false} if generated keys are not needed, {@code true} if
* generated keys should be configured automatically, {@code int[]}
* to specify column indices to return generated keys from, or
* {@code String[]} to specify column names to return generated keys
* from
*/
public void clear(Object generatedKeysRequest) { public void clear(Object generatedKeysRequest) {
this.generatedKeysRequest = generatedKeysRequest; this.generatedKeysRequest = generatedKeysRequest;
data.clear(); data.clear();
row.clear(); row.clear();
columns.clear(); allColumns.clear();
table = null; table = null;
} }
public void initialize(Table table) { /**
this.table = table; * Saves row with generated keys if any.
} *
* @param tableRow
public void confirmRow() { * table row that was inserted
*/
public void confirmRow(Row tableRow) {
if (Boolean.FALSE.equals(generatedKeysRequest)) { if (Boolean.FALSE.equals(generatedKeysRequest)) {
return; return;
} }
int size = row.size(); int size = row.size();
if (size > 0) { if (size > 0) {
if (size == 2) { if (size == 1) {
Column column = (Column) row.get(0); Column column = row.get(0);
data.add(Collections.singletonMap(column, row.get(1))); data.add(Collections.singletonMap(column, tableRow.getValue(column.getColumnId()).getObject()));
if (!columns.contains(column)) { if (!allColumns.contains(column)) {
columns.add(column); allColumns.add(column);
} }
} else { } else {
HashMap<Column, Object> map = new HashMap<>(); HashMap<Column, Object> map = new HashMap<>();
for (int i = 0; i < size; i += 2) { for (Column column : row) {
Column column = (Column) row.get(i); map.put(column, tableRow.getValue(column.getColumnId()).getObject());
map.put(column, row.get(i + 1)); if (!allColumns.contains(column)) {
if (!columns.contains(column)) { allColumns.add(column);
columns.add(column);
} }
} }
data.add(map); data.add(map);
...@@ -80,13 +115,18 @@ public final class GeneratedKeys { ...@@ -80,13 +115,18 @@ public final class GeneratedKeys {
} }
} }
/**
* Returns generated keys.
*
* @return result set with generated keys
*/
public SimpleResultSet getKeys() { public SimpleResultSet getKeys() {
SimpleResultSet rs = new SimpleResultSet(); SimpleResultSet rs = new SimpleResultSet();
if (Boolean.FALSE.equals(generatedKeysRequest)) { if (Boolean.FALSE.equals(generatedKeysRequest)) {
return rs; return rs;
} }
if (Boolean.TRUE.equals(generatedKeysRequest)) { if (Boolean.TRUE.equals(generatedKeysRequest)) {
for (Column column : columns) { for (Column column : allColumns) {
rs.addColumn(column.getName(), DataType.convertTypeToSQLType(column.getType()), rs.addColumn(column.getName(), DataType.convertTypeToSQLType(column.getType()),
MathUtils.convertLongToInt(column.getPrecision()), column.getScale()); MathUtils.convertLongToInt(column.getPrecision()), column.getScale());
} }
...@@ -95,13 +135,13 @@ public final class GeneratedKeys { ...@@ -95,13 +135,13 @@ public final class GeneratedKeys {
int[] indices = (int[]) generatedKeysRequest; int[] indices = (int[]) generatedKeysRequest;
Column[] columns = table.getColumns(); Column[] columns = table.getColumns();
int cnt = columns.length; int cnt = columns.length;
this.columns.clear(); this.allColumns.clear();
for (int idx : indices) { for (int idx : indices) {
if (idx >= 1 && idx <= cnt) { if (idx >= 1 && idx <= cnt) {
Column column = columns[idx - 1]; Column column = columns[idx - 1];
rs.addColumn(column.getName(), DataType.convertTypeToSQLType(column.getType()), rs.addColumn(column.getName(), DataType.convertTypeToSQLType(column.getType()),
MathUtils.convertLongToInt(column.getPrecision()), column.getScale()); MathUtils.convertLongToInt(column.getPrecision()), column.getScale());
this.columns.add(column); this.allColumns.add(column);
} }
} }
} else { } else {
...@@ -110,13 +150,13 @@ public final class GeneratedKeys { ...@@ -110,13 +150,13 @@ public final class GeneratedKeys {
} else if (generatedKeysRequest instanceof String[]) { } else if (generatedKeysRequest instanceof String[]) {
if (table != null) { if (table != null) {
String[] names = (String[]) generatedKeysRequest; String[] names = (String[]) generatedKeysRequest;
this.columns.clear(); this.allColumns.clear();
for (String name : names) { for (String name : names) {
try { try {
Column column = table.getColumn(name); Column column = table.getColumn(name);
rs.addColumn(column.getName(), DataType.convertTypeToSQLType(column.getType()), rs.addColumn(column.getName(), DataType.convertTypeToSQLType(column.getType()),
MathUtils.convertLongToInt(column.getPrecision()), column.getScale()); MathUtils.convertLongToInt(column.getPrecision()), column.getScale());
this.columns.add(column); this.allColumns.add(column);
} catch (DbException e) { } catch (DbException e) {
} }
} }
...@@ -130,9 +170,9 @@ public final class GeneratedKeys { ...@@ -130,9 +170,9 @@ public final class GeneratedKeys {
return rs; return rs;
} }
for (Map<Column, Object> map : data) { for (Map<Column, Object> map : data) {
Object[] row = new Object[columns.size()]; Object[] row = new Object[allColumns.size()];
for (Map.Entry<Column, Object> entry : map.entrySet()) { for (Map.Entry<Column, Object> entry : map.entrySet()) {
int idx = columns.indexOf(entry.getKey()); int idx = allColumns.indexOf(entry.getKey());
if (idx >= 0) { if (idx >= 0) {
row[idx] = entry.getValue(); row[idx] = entry.getValue();
} }
...@@ -142,13 +182,29 @@ public final class GeneratedKeys { ...@@ -142,13 +182,29 @@ public final class GeneratedKeys {
return rs; return rs;
} }
/**
* Initializes processing of the specified table. Should be called after
* {@code clear()}, but before other methods.
*
* @param table
* table
*/
public void initialize(Table table) {
this.table = table;
}
/**
* Clears unsaved information about previous row, if any. Should be called
* before processing of a new row if previous row was not confirmed or simply
* always before each row.
*/
public void nextRow() { public void nextRow() {
row.clear(); row.clear();
} }
@Override @Override
public String toString() { public String toString() {
return columns + ": " + data.size(); return allColumns + ": " + data.size();
} }
} }
...@@ -261,7 +261,7 @@ public class TriggerObject extends SchemaObjectBase { ...@@ -261,7 +261,7 @@ public class TriggerObject extends SchemaObjectBase {
Object o = newList[i]; Object o = newList[i];
if (o != newListBackup[i]) { if (o != newListBackup[i]) {
Value v = DataType.convertToValue(session, o, Value.UNKNOWN); Value v = DataType.convertToValue(session, o, Value.UNKNOWN);
session.getGeneratedKeys().add(table.getColumn(i), v); session.getGeneratedKeys().add(table.getColumn(i));
newRow.setValue(i, v); newRow.setValue(i, v);
} }
} }
......
...@@ -321,7 +321,7 @@ public class Column { ...@@ -321,7 +321,7 @@ public class Column {
value = ValueNull.INSTANCE; value = ValueNull.INSTANCE;
} else { } else {
value = localDefaultExpression.getValue(session).convertTo(type); value = localDefaultExpression.getValue(session).convertTo(type);
session.getGeneratedKeys().add(this, value); session.getGeneratedKeys().add(this);
if (primaryKey) { if (primaryKey) {
session.setLastIdentity(value); session.setLastIdentity(value);
} }
...@@ -331,7 +331,7 @@ public class Column { ...@@ -331,7 +331,7 @@ public class Column {
if (value == ValueNull.INSTANCE) { if (value == ValueNull.INSTANCE) {
if (convertNullToDefault) { if (convertNullToDefault) {
value = localDefaultExpression.getValue(session).convertTo(type); value = localDefaultExpression.getValue(session).convertTo(type);
session.getGeneratedKeys().add(this, value); session.getGeneratedKeys().add(this);
} }
if (value == ValueNull.INSTANCE && !nullable) { if (value == ValueNull.INSTANCE && !nullable) {
if (mode.convertInsertNullToZero) { if (mode.convertInsertNullToZero) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论