提交 58a30eba authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Return generated keys only if explicitly requested

上级 6fc3314f
......@@ -149,7 +149,7 @@ public abstract class Command implements CommandInterface {
@Override
public void stop() {
session.endStatement();
session.setCurrentCommand(null);
session.setCurrentCommand(null, false);
if (!isTransactional()) {
session.commit(true);
} else if (session.getAutoCommit()) {
......@@ -193,7 +193,7 @@ public abstract class Command implements CommandInterface {
}
}
synchronized (sync) {
session.setCurrentCommand(this);
session.setCurrentCommand(this, false);
try {
while (true) {
database.checkPowerOff();
......@@ -238,7 +238,7 @@ public abstract class Command implements CommandInterface {
}
@Override
public int executeUpdate() {
public int executeUpdate(Object generatedKeysRequest) {
long start = 0;
Database database = session.getDatabase();
Object sync = database.isMultiThreaded() ? (Object) session : (Object) database;
......@@ -252,7 +252,7 @@ public abstract class Command implements CommandInterface {
}
synchronized (sync) {
Session.Savepoint rollback = session.setSavepoint();
session.setCurrentCommand(this);
session.setCurrentCommand(this, generatedKeysRequest);
try {
while (true) {
database.checkPowerOff();
......
......@@ -510,9 +510,16 @@ public interface CommandInterface {
/**
* Execute the statement
*
* @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
*
* @return the update count
*/
int executeUpdate();
int executeUpdate(Object generatedKeysRequest);
/**
* Stop the command execution, release all locks and resources
......
......@@ -39,7 +39,7 @@ class CommandList extends Command {
@Override
public int update() {
int updateCount = command.executeUpdate();
int updateCount = command.executeUpdate(false);
executeRemaining();
return updateCount;
}
......
......@@ -194,7 +194,7 @@ public class CommandRemote implements CommandInterface {
}
@Override
public int executeUpdate() {
public int executeUpdate(Object generatedKeys) {
checkParameters();
synchronized (session) {
int updateCount = 0;
......@@ -206,6 +206,29 @@ public class CommandRemote implements CommandInterface {
session.traceOperation("COMMAND_EXECUTE_UPDATE", id);
transfer.writeInt(SessionRemote.COMMAND_EXECUTE_UPDATE).writeInt(id);
sendParameters(transfer);
if (session.getClientVersion() >= Constants.TCP_PROTOCOL_VERSION_17) {
if (Boolean.FALSE.equals(generatedKeys)) {
transfer.writeInt(0);
} else if (Boolean.TRUE.equals(generatedKeys)) {
transfer.writeInt(1);
} else if (generatedKeys instanceof int[]) {
int[] keys = (int[]) generatedKeys;
transfer.writeInt(2);
transfer.writeInt(keys.length);
for (int key : keys) {
transfer.writeInt(key);
}
} else if (generatedKeys instanceof String[]) {
String[] keys = (String[]) generatedKeys;
transfer.writeInt(3);
transfer.writeInt(keys.length);
for (String key : keys) {
transfer.writeString(key);
}
} else {
transfer.writeInt(0);
}
}
session.done(transfer);
updateCount = transfer.readInt();
autoCommit = transfer.readBoolean();
......
......@@ -148,6 +148,7 @@ public class Insert extends Prepared implements ResultTarget {
if (listSize > 0) {
int columnLen = columns.length;
GeneratedKeys generatedKeys = session.getGeneratedKeys();
generatedKeys.initialize(table);
for (int x = 0; x < listSize; x++) {
session.startStatementWithinTransaction();
generatedKeys.nextRow();
......
......@@ -90,6 +90,7 @@ public class Merge extends Prepared {
// process values in list
count = 0;
GeneratedKeys generatedKeys = session.getGeneratedKeys();
generatedKeys.initialize(targetTable);
for (int x = 0, size = valuesExpressionList.size(); x < size; x++) {
setCurrentRowNumber(x + 1);
generatedKeys.nextRow();
......
......@@ -100,6 +100,11 @@ public class Constants {
*/
public static final int TCP_PROTOCOL_VERSION_16 = 16;
/**
* The TCP protocol version number 17.
*/
public static final int TCP_PROTOCOL_VERSION_17 = 17;
/**
* The major version of this database.
*/
......
......@@ -203,7 +203,7 @@ public class Engine implements SessionFactory {
CommandInterface command = session.prepareCommand(
"SET " + Parser.quoteIdentifier(setting) + " " + value,
Integer.MAX_VALUE);
command.executeUpdate();
command.executeUpdate(false);
} catch (DbException e) {
if (e.getErrorCode() == ErrorCode.ADMIN_RIGHTS_REQUIRED) {
session.getTrace().error(e, "admin rights required; user: \"" +
......@@ -221,7 +221,7 @@ public class Engine implements SessionFactory {
try {
CommandInterface command = session.prepareCommand(init,
Integer.MAX_VALUE);
command.executeUpdate();
command.executeUpdate(false);
} catch (DbException e) {
if (!ignoreUnknownSetting) {
session.close();
......
......@@ -10,7 +10,9 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.h2.message.DbException;
import org.h2.table.Column;
import org.h2.table.Table;
import org.h2.tools.SimpleResultSet;
import org.h2.util.MathUtils;
import org.h2.util.New;
......@@ -27,18 +29,34 @@ public final class GeneratedKeys {
private final ArrayList<Column> columns = New.arrayList();
private Object generatedKeysRequest;
private Table table;
public void add(Column column, Value value) {
if (Boolean.FALSE.equals(generatedKeysRequest)) {
return;
}
row.add(column);
row.add(value.getObject());
}
public void clear() {
public void clear(Object generatedKeysRequest) {
this.generatedKeysRequest = generatedKeysRequest;
data.clear();
row.clear();
columns.clear();
table = null;
}
public void initialize(Table table) {
this.table = table;
}
public void confirmRow() {
if (Boolean.FALSE.equals(generatedKeysRequest)) {
return;
}
int size = row.size();
if (size > 0) {
if (size == 2) {
......@@ -64,14 +82,56 @@ public final class GeneratedKeys {
public SimpleResultSet getKeys() {
SimpleResultSet rs = new SimpleResultSet();
for (Column column : columns) {
rs.addColumn(column.getName(), DataType.convertTypeToSQLType(column.getType()),
MathUtils.convertLongToInt(column.getPrecision()), column.getScale());
if (Boolean.FALSE.equals(generatedKeysRequest)) {
return rs;
}
if (Boolean.TRUE.equals(generatedKeysRequest)) {
for (Column column : columns) {
rs.addColumn(column.getName(), DataType.convertTypeToSQLType(column.getType()),
MathUtils.convertLongToInt(column.getPrecision()), column.getScale());
}
} else if (generatedKeysRequest instanceof int[]) {
if (table != null) {
int[] indices = (int[]) generatedKeysRequest;
Column[] columns = table.getColumns();
int cnt = columns.length;
for (int idx : indices) {
if (idx >= 1 && idx <= cnt) {
Column column = columns[idx - 1];
rs.addColumn(column.getName(), DataType.convertTypeToSQLType(column.getType()),
MathUtils.convertLongToInt(column.getPrecision()), column.getScale());
}
}
} else {
return rs;
}
} else if (generatedKeysRequest instanceof String[]) {
if (table != null) {
String[] names = (String[]) generatedKeysRequest;
for (String name : names) {
try {
Column column = table.getColumn(name);
rs.addColumn(column.getName(), DataType.convertTypeToSQLType(column.getType()),
MathUtils.convertLongToInt(column.getPrecision()), column.getScale());
} catch (DbException e) {
}
}
} else {
return rs;
}
} else {
return rs;
}
if (rs.getColumnCount() == 0) {
return rs;
}
for (Map<Column, Object> map : data) {
Object[] row = new Object[columns.size()];
for (Map.Entry<Column, Object> entry : map.entrySet()) {
row[columns.indexOf(entry.getKey())] = entry.getValue();
int idx = columns.indexOf(entry.getKey());
if (idx >= 0) {
row[idx] = entry.getValue();
}
}
rs.addRow(row);
}
......
......@@ -1245,13 +1245,19 @@ public class Session extends SessionWithState {
* executing the statement.
*
* @param command the command
*/
public void setCurrentCommand(Command command) {
* @param generated keys request
* {@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 setCurrentCommand(Command command, Object generatedKeysRequest) {
this.currentCommand = command;
// Preserve generated keys in case of a new query so they can be read with
// CALL GET_GENERATED_KEYS()
if (command != null && !command.isQuery() && generatedKeys != null) {
generatedKeys.clear();
if (command != null && !command.isQuery()) {
getGeneratedKeys().clear(generatedKeysRequest);
}
if (queryTimeout > 0 && command != null) {
currentCommandStart = System.currentTimeMillis();
......
......@@ -118,7 +118,7 @@ public class SessionRemote extends SessionWithState implements DataHandler {
trans.setSSL(ci.isSSL());
trans.init();
trans.writeInt(Constants.TCP_PROTOCOL_VERSION_6);
trans.writeInt(Constants.TCP_PROTOCOL_VERSION_16);
trans.writeInt(Constants.TCP_PROTOCOL_VERSION_17);
trans.writeString(db);
trans.writeString(ci.getOriginalURL());
trans.writeString(ci.getUserName());
......@@ -210,7 +210,7 @@ public class SessionRemote extends SessionWithState implements DataHandler {
CommandInterface c = prepareCommand(
"SET CLUSTER " + serverList, Integer.MAX_VALUE);
// this will set autoCommit to false
c.executeUpdate();
c.executeUpdate(false);
// so we need to switch it on
autoCommit = true;
cluster = true;
......@@ -265,13 +265,13 @@ public class SessionRemote extends SessionWithState implements DataHandler {
autoCommitTrue = prepareCommand(
"SET AUTOCOMMIT TRUE", Integer.MAX_VALUE);
}
autoCommitTrue.executeUpdate();
autoCommitTrue.executeUpdate(false);
} else {
if (autoCommitFalse == null) {
autoCommitFalse = prepareCommand(
"SET AUTOCOMMIT FALSE", Integer.MAX_VALUE);
}
autoCommitFalse.executeUpdate();
autoCommitFalse.executeUpdate(false);
}
}
}
......@@ -468,7 +468,7 @@ public class SessionRemote extends SessionWithState implements DataHandler {
private void switchOffCluster() {
CommandInterface ci = prepareCommand("SET CLUSTER ''", Integer.MAX_VALUE);
ci.executeUpdate();
ci.executeUpdate(false);
}
/**
......
......@@ -29,7 +29,7 @@ abstract class SessionWithState implements SessionInterface {
try {
for (String sql : sessionState) {
CommandInterface ci = prepareCommand(sql, Integer.MAX_VALUE);
ci.executeUpdate();
ci.executeUpdate(false);
}
} finally {
sessionStateUpdating = false;
......
......@@ -950,7 +950,8 @@ public class FullText {
useOwnConnection = isMultiThread(conn);
if(!useOwnConnection) {
for (int i = 0; i < SQL.length; i++) {
prepStatements[i] = conn.prepareStatement(SQL[i]);
prepStatements[i] = conn.prepareStatement(SQL[i],
Statement.RETURN_GENERATED_KEYS);
}
}
}
......@@ -1154,7 +1155,9 @@ public class FullText {
}
private PreparedStatement getStatement(Connection conn, int index) throws SQLException {
return useOwnConnection ? conn.prepareStatement(SQL[index]) : prepStatements[index];
return useOwnConnection ?
conn.prepareStatement(SQL[index], Statement.RETURN_GENERATED_KEYS)
: prepStatements[index];
}
}
......
......@@ -47,7 +47,7 @@ public class JdbcCallableStatement extends JdbcPreparedStatement implements
JdbcCallableStatement(JdbcConnection conn, String sql, int id,
int resultSetType, int resultSetConcurrency) {
super(conn, sql, id, resultSetType, resultSetConcurrency, false);
super(conn, sql, id, resultSetType, resultSetConcurrency, false, false);
setTrace(session.getTrace(), TraceObject.CALLABLE_STATEMENT, id);
}
......
......@@ -300,7 +300,7 @@ public class JdbcConnection extends TraceObject
sql = translateSQL(sql);
return new JdbcPreparedStatement(this, sql, id,
ResultSet.TYPE_FORWARD_ONLY,
Constants.DEFAULT_RESULT_SET_CONCURRENCY, false);
Constants.DEFAULT_RESULT_SET_CONCURRENCY, false, false);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -326,7 +326,7 @@ public class JdbcConnection extends TraceObject
sql = translateSQL(sql);
return new JdbcPreparedStatement(this, sql, id,
ResultSet.TYPE_FORWARD_ONLY,
Constants.DEFAULT_RESULT_SET_CONCURRENCY, true);
Constants.DEFAULT_RESULT_SET_CONCURRENCY, true, false);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -491,7 +491,7 @@ public class JdbcConnection extends TraceObject
checkClosedForWrite();
try {
commit = prepareCommand("COMMIT", commit);
commit.executeUpdate();
commit.executeUpdate(false);
} finally {
afterWriting();
}
......@@ -689,7 +689,7 @@ public class JdbcConnection extends TraceObject
checkClosed();
sql = translateSQL(sql);
return new JdbcPreparedStatement(this, sql, id, resultSetType,
resultSetConcurrency, false);
resultSetConcurrency, false, false);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -744,7 +744,7 @@ public class JdbcConnection extends TraceObject
setLockMode = prepareCommand("SET LOCK_MODE ?", setLockMode);
setLockMode.getParameters().get(0).setValue(ValueInt.get(lockMode),
false);
setLockMode.executeUpdate();
setLockMode.executeUpdate(false);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -761,7 +761,7 @@ public class JdbcConnection extends TraceObject
setQueryTimeout);
setQueryTimeout.getParameters().get(0)
.setValue(ValueInt.get(seconds * 1000), false);
setQueryTimeout.executeUpdate();
setQueryTimeout.executeUpdate(false);
queryTimeoutCache = seconds;
} catch (Exception e) {
throw logAndConvert(e);
......@@ -1017,7 +1017,7 @@ public class JdbcConnection extends TraceObject
CommandInterface set = prepareCommand(
"SAVEPOINT " + JdbcSavepoint.getName(null, savepointId),
Integer.MAX_VALUE);
set.executeUpdate();
set.executeUpdate(false);
JdbcSavepoint savepoint = new JdbcSavepoint(this, savepointId, null,
trace, id);
savepointId++;
......@@ -1045,7 +1045,7 @@ public class JdbcConnection extends TraceObject
CommandInterface set = prepareCommand(
"SAVEPOINT " + JdbcSavepoint.getName(name, 0),
Integer.MAX_VALUE);
set.executeUpdate();
set.executeUpdate(false);
JdbcSavepoint savepoint = new JdbcSavepoint(this, 0, name, trace,
id);
return savepoint;
......@@ -1131,7 +1131,7 @@ public class JdbcConnection extends TraceObject
checkClosed();
sql = translateSQL(sql);
return new JdbcPreparedStatement(this, sql, id, resultSetType,
resultSetConcurrency, false);
resultSetConcurrency, false, false);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -1151,11 +1151,19 @@ public class JdbcConnection extends TraceObject
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
throws SQLException {
try {
int id = getNextId(TraceObject.PREPARED_STATEMENT);
if (isDebugEnabled()) {
debugCode("prepareStatement(" + quote(sql) + ", "
+ autoGeneratedKeys + ");");
debugCodeAssign("PreparedStatement",
TraceObject.PREPARED_STATEMENT, id,
"prepareStatement(" + quote(sql) + ", "
+ autoGeneratedKeys + ");");
}
return prepareStatement(sql);
checkClosed();
sql = translateSQL(sql);
return new JdbcPreparedStatement(this, sql, id,
ResultSet.TYPE_FORWARD_ONLY,
Constants.DEFAULT_RESULT_SET_CONCURRENCY, false,
autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -1175,11 +1183,18 @@ public class JdbcConnection extends TraceObject
public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
throws SQLException {
try {
int id = getNextId(TraceObject.PREPARED_STATEMENT);
if (isDebugEnabled()) {
debugCode("prepareStatement(" + quote(sql) + ", "
+ quoteIntArray(columnIndexes) + ");");
debugCodeAssign("PreparedStatement",
TraceObject.PREPARED_STATEMENT, id,
"prepareStatement(" + quote(sql) + ", "
+ quoteIntArray(columnIndexes) + ");");
}
return prepareStatement(sql);
checkClosed();
sql = translateSQL(sql);
return new JdbcPreparedStatement(this, sql, id,
ResultSet.TYPE_FORWARD_ONLY,
Constants.DEFAULT_RESULT_SET_CONCURRENCY, false, columnIndexes);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -1199,11 +1214,18 @@ public class JdbcConnection extends TraceObject
public PreparedStatement prepareStatement(String sql, String[] columnNames)
throws SQLException {
try {
int id = getNextId(TraceObject.PREPARED_STATEMENT);
if (isDebugEnabled()) {
debugCode("prepareStatement(" + quote(sql) + ", "
+ quoteArray(columnNames) + ");");
debugCodeAssign("PreparedStatement",
TraceObject.PREPARED_STATEMENT, id,
"prepareStatement(" + quote(sql) + ", "
+ quoteArray(columnNames) + ");");
}
return prepareStatement(sql);
checkClosed();
sql = translateSQL(sql);
return new JdbcPreparedStatement(this, sql, id,
ResultSet.TYPE_FORWARD_ONLY,
Constants.DEFAULT_RESULT_SET_CONCURRENCY, false, columnNames);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -1530,7 +1552,7 @@ public class JdbcConnection extends TraceObject
private void rollbackInternal() {
rollback = prepareCommand("ROLLBACK", rollback);
rollback.executeUpdate();
rollback.executeUpdate(false);
}
/**
......
......@@ -63,11 +63,13 @@ public class JdbcPreparedStatement extends JdbcStatement implements
private ArrayList<Value[]> batchParameters;
private MergedResultSet batchIdentities;
private HashMap<String, Integer> cachedColumnLabelMap;
private final Object generatedKeysRequest;
JdbcPreparedStatement(JdbcConnection conn, String sql, int id,
int resultSetType, int resultSetConcurrency,
boolean closeWithResultSet) {
boolean closeWithResultSet, Object generatedKeysRequest) {
super(conn, id, resultSetType, resultSetConcurrency, closeWithResultSet);
this.generatedKeysRequest = generatedKeysRequest;
setTrace(session.getTrace(), TraceObject.PREPARED_STATEMENT, id);
this.sqlStatement = sql;
command = conn.prepareCommand(sql, fetchSize);
......@@ -193,7 +195,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements
synchronized (session) {
try {
setExecutingStatement(command);
updateCount = command.executeUpdate();
updateCount = command.executeUpdate(generatedKeysRequest);
} finally {
setExecutingStatement(null);
}
......@@ -236,7 +238,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements
updatable, cachedColumnLabelMap);
} else {
returnsResultSet = false;
updateCount = command.executeUpdate();
updateCount = command.executeUpdate(generatedKeysRequest);
}
} finally {
if (!lazy) {
......
......@@ -65,7 +65,7 @@ public class JdbcSavepoint extends TraceObject implements Savepoint {
checkValid();
conn.prepareCommand(
"ROLLBACK TO SAVEPOINT " + getName(name, savepointId),
Integer.MAX_VALUE).executeUpdate();
Integer.MAX_VALUE).executeUpdate(false);
}
private void checkValid() {
......
......@@ -120,7 +120,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
public int executeUpdate(String sql) throws SQLException {
try {
debugCodeCall("executeUpdate", sql);
return executeUpdateInternal(sql);
return executeUpdateInternal(sql, false);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -148,13 +148,13 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
public long executeLargeUpdate(String sql) throws SQLException {
try {
debugCodeCall("executeLargeUpdate", sql);
return executeUpdateInternal(sql);
return executeUpdateInternal(sql, false);
} catch (Exception e) {
throw logAndConvert(e);
}
}
private int executeUpdateInternal(String sql) throws SQLException {
private int executeUpdateInternal(String sql, Object generatedKeysRequest) throws SQLException {
checkClosedForWrite();
try {
closeOldResultSet();
......@@ -163,7 +163,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
synchronized (session) {
setExecutingStatement(command);
try {
updateCount = command.executeUpdate();
updateCount = command.executeUpdate(generatedKeysRequest);
} finally {
setExecutingStatement(null);
}
......@@ -191,13 +191,13 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
public boolean execute(String sql) throws SQLException {
try {
debugCodeCall("execute", sql);
return executeInternal(sql);
return executeInternal(sql, false);
} catch (Exception e) {
throw logAndConvert(e);
}
}
private boolean executeInternal(String sql) throws SQLException {
private boolean executeInternal(String sql, Object generatedKeysRequest) throws SQLException {
int id = getNextId(TraceObject.RESULT_SET);
checkClosedForWrite();
try {
......@@ -219,7 +219,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
closedByResultSet, scrollable, updatable);
} else {
returnsResultSet = false;
updateCount = command.executeUpdate();
updateCount = command.executeUpdate(generatedKeysRequest);
}
} finally {
if (!lazy) {
......@@ -756,7 +756,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
for (int i = 0; i < size; i++) {
String sql = batchCommands.get(i);
try {
result[i] = executeUpdateInternal(sql);
result[i] = executeUpdateInternal(sql, false);
} catch (Exception re) {
SQLException e = logAndConvert(re);
if (next == null) {
......@@ -894,7 +894,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
if (isDebugEnabled()) {
debugCode("executeUpdate("+quote(sql)+", "+autoGeneratedKeys+");");
}
return executeUpdateInternal(sql);
return executeUpdateInternal(sql, autoGeneratedKeys == RETURN_GENERATED_KEYS);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -919,7 +919,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
if (isDebugEnabled()) {
debugCode("executeLargeUpdate("+quote(sql)+", "+autoGeneratedKeys+");");
}
return executeUpdateInternal(sql);
return executeUpdateInternal(sql, autoGeneratedKeys == RETURN_GENERATED_KEYS);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -944,7 +944,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
if (isDebugEnabled()) {
debugCode("executeUpdate("+quote(sql)+", "+quoteIntArray(columnIndexes)+");");
}
return executeUpdateInternal(sql);
return executeUpdateInternal(sql, columnIndexes);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -969,7 +969,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
if (isDebugEnabled()) {
debugCode("executeLargeUpdate("+quote(sql)+", "+quoteIntArray(columnIndexes)+");");
}
return executeUpdateInternal(sql);
return executeUpdateInternal(sql, columnIndexes);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -994,7 +994,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
if (isDebugEnabled()) {
debugCode("executeUpdate("+quote(sql)+", "+quoteArray(columnNames)+");");
}
return executeUpdateInternal(sql);
return executeUpdateInternal(sql, columnNames);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -1019,7 +1019,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
if (isDebugEnabled()) {
debugCode("executeLargeUpdate("+quote(sql)+", "+quoteArray(columnNames)+");");
}
return executeUpdateInternal(sql);
return executeUpdateInternal(sql, columnNames);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -1044,7 +1044,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
if (isDebugEnabled()) {
debugCode("execute("+quote(sql)+", "+autoGeneratedKeys+");");
}
return executeInternal(sql);
return executeInternal(sql, autoGeneratedKeys == RETURN_GENERATED_KEYS);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -1069,7 +1069,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
if (isDebugEnabled()) {
debugCode("execute("+quote(sql)+", "+quoteIntArray(columnIndexes)+");");
}
return executeInternal(sql);
return executeInternal(sql, columnIndexes);
} catch (Exception e) {
throw logAndConvert(e);
}
......@@ -1094,7 +1094,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
if (isDebugEnabled()) {
debugCode("execute("+quote(sql)+", "+quoteArray(columnNames)+");");
}
return executeInternal(sql);
return executeInternal(sql, columnNames);
} catch (Exception e) {
throw logAndConvert(e);
}
......
......@@ -91,12 +91,12 @@ public class TcpServerThread implements Runnable {
if (maxClientVersion < Constants.TCP_PROTOCOL_VERSION_6) {
throw DbException.get(ErrorCode.DRIVER_VERSION_ERROR_2,
"" + clientVersion, "" + Constants.TCP_PROTOCOL_VERSION_6);
} else if (minClientVersion > Constants.TCP_PROTOCOL_VERSION_16) {
} else if (minClientVersion > Constants.TCP_PROTOCOL_VERSION_17) {
throw DbException.get(ErrorCode.DRIVER_VERSION_ERROR_2,
"" + clientVersion, "" + Constants.TCP_PROTOCOL_VERSION_16);
"" + clientVersion, "" + Constants.TCP_PROTOCOL_VERSION_17);
}
if (maxClientVersion >= Constants.TCP_PROTOCOL_VERSION_16) {
clientVersion = Constants.TCP_PROTOCOL_VERSION_16;
if (maxClientVersion >= Constants.TCP_PROTOCOL_VERSION_17) {
clientVersion = Constants.TCP_PROTOCOL_VERSION_17;
} else {
clientVersion = maxClientVersion;
}
......@@ -178,7 +178,7 @@ public class TcpServerThread implements Runnable {
RuntimeException closeError = null;
try {
Command rollback = session.prepareLocal("ROLLBACK");
rollback.executeUpdate();
rollback.executeUpdate(false);
} catch (RuntimeException e) {
closeError = e;
server.traceError(e);
......@@ -302,7 +302,7 @@ public class TcpServerThread implements Runnable {
commit = session.prepareLocal("COMMIT");
}
int old = session.getModificationId();
commit.executeUpdate();
commit.executeUpdate(false);
transfer.writeInt(getState(old)).flush();
break;
}
......@@ -353,10 +353,41 @@ public class TcpServerThread implements Runnable {
int id = transfer.readInt();
Command command = (Command) cache.getObject(id, false);
setParameters(command);
Object generatedKeysRequest;
if (clientVersion >= Constants.TCP_PROTOCOL_VERSION_17) {
int type = transfer.readInt();
switch (type) {
default:
generatedKeysRequest = false;
break;
case 1:
generatedKeysRequest = true;
break;
case 2: {
int len = transfer.readInt();
int[] keys = new int[len];
for (int i = 0; i < len; i++) {
keys[i] = transfer.readInt();
}
generatedKeysRequest = keys;
break;
}
case 3: {
int len = transfer.readInt();
String[] keys = new String[len];
for (int i = 0; i < len; i++) {
keys[i] = transfer.readString();
}
generatedKeysRequest = keys;
}
}
} else {
generatedKeysRequest = true;
}
int old = session.getModificationId();
int updateCount;
synchronized (session) {
updateCount = command.executeUpdate();
updateCount = command.executeUpdate(generatedKeysRequest);
}
int status;
if (session.isClosed()) {
......
......@@ -1284,7 +1284,7 @@ public class WebApp {
ResultSet rs;
long time = System.currentTimeMillis();
boolean metadata = false;
boolean generatedKeys = false;
int generatedKeys = Statement.NO_GENERATED_KEYS;
boolean edit = false;
boolean list = false;
if (isBuiltIn(sql, "@autocommit_true")) {
......@@ -1316,7 +1316,7 @@ public class WebApp {
sql = sql.substring("@meta".length()).trim();
}
if (isBuiltIn(sql, "@generated")) {
generatedKeys = true;
generatedKeys = Statement.RETURN_GENERATED_KEYS;
sql = sql.substring("@generated".length()).trim();
} else if (isBuiltIn(sql, "@history")) {
buff.append(getCommandHistoryString());
......@@ -1385,9 +1385,9 @@ public class WebApp {
int maxrows = getMaxrows();
stat.setMaxRows(maxrows);
session.executingStatement = stat;
boolean isResultSet = stat.execute(sql);
boolean isResultSet = stat.execute(sql, generatedKeys);
session.addCommand(sql);
if (generatedKeys) {
if (generatedKeys == Statement.RETURN_GENERATED_KEYS) {
rs = null;
rs = stat.getGeneratedKeys();
} else {
......
......@@ -211,7 +211,7 @@ public class FileLock implements Runnable {
Transfer transfer = new Transfer(null, socket);
transfer.init();
transfer.writeInt(Constants.TCP_PROTOCOL_VERSION_6);
transfer.writeInt(Constants.TCP_PROTOCOL_VERSION_16);
transfer.writeInt(Constants.TCP_PROTOCOL_VERSION_17);
transfer.writeString(null);
transfer.writeString(null);
transfer.writeString(id);
......
......@@ -526,7 +526,7 @@ public class TestPreparedStatement extends TestBase {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST_UUID(id UUID DEFAULT " +
"random_UUID() PRIMARY KEY)");
stat.execute("INSERT INTO TEST_UUID() VALUES()");
stat.execute("INSERT INTO TEST_UUID() VALUES()", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stat.getGeneratedKeys();
rs.next();
byte[] data = rs.getBytes(1);
......@@ -573,7 +573,7 @@ public class TestPreparedStatement extends TestBase {
stat.execute("create sequence seq start with 1000");
stat.execute("create trigger test_ins after insert on test call \"" +
SequenceTrigger.class.getName() + "\"");
stat.execute("insert into test values(null)");
stat.execute("insert into test values(null)", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stat.getGeneratedKeys();
rs.next();
// Generated key
......@@ -1275,7 +1275,7 @@ public class TestPreparedStatement extends TestBase {
stat.execute("CREATE TABLE TEST(ID INT)");
PreparedStatement prep;
prep = conn.prepareStatement(
"INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)");
"INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)", Statement.RETURN_GENERATED_KEYS);
prep.execute();
ResultSet rs = prep.getGeneratedKeys();
rs.next();
......@@ -1317,7 +1317,6 @@ public class TestPreparedStatement extends TestBase {
prep.execute();
rs = prep.getGeneratedKeys();
rs.next();
assertEquals(5, rs.getInt(1));
assertFalse(rs.next());
stat.execute("DROP TABLE TEST");
......@@ -1369,7 +1368,8 @@ public class TestPreparedStatement extends TestBase {
stat.execute("drop sequence seq");
stat.execute("create table test(id bigint auto_increment, value int)");
stat.execute("insert into test(value) values (1), (2)");
stat.execute("insert into test(value) values (1), (2)",
Statement.RETURN_GENERATED_KEYS);
rs = stat.getGeneratedKeys();
rs.next();
assertEquals(1L, rs.getLong(1));
......@@ -1409,7 +1409,8 @@ public class TestPreparedStatement extends TestBase {
assertFalse(u1.equals(u2));
assertFalse(u2.equals(u3));
assertFalse(u3.equals(u4));
prep = conn.prepareStatement("merge into test(id, value) key (id) values (?, ?)");
prep = conn.prepareStatement("merge into test(id, value) key (id) values (?, ?)",
Statement.RETURN_GENERATED_KEYS);
prep.setObject(1, 2);
prep.setInt(2, 10);
prep.execute();
......@@ -1427,7 +1428,8 @@ public class TestPreparedStatement extends TestBase {
stat.execute("create trigger test_insert before insert on test for each row call \""
+ TestGeneratedKeysTrigger.class.getName()
+ '"');
stat.executeUpdate("insert into test(value) values (10), (20)");
stat.executeUpdate("insert into test(value) values (10), (20)",
Statement.RETURN_GENERATED_KEYS);
rs = stat.getGeneratedKeys();
rs.next();
u1 = (UUID) rs.getObject(1);
......@@ -1442,10 +1444,68 @@ public class TestPreparedStatement extends TestBase {
stat.execute("drop trigger test_insert");
stat.execute("drop table test");
stat.execute("create table test(id bigint auto_increment, value int)");
stat.execute("insert into test(value) values (1)");
assertFalse(stat.getGeneratedKeys().next());
stat.execute("insert into test(value) values (1)", Statement.NO_GENERATED_KEYS);
assertFalse(stat.getGeneratedKeys().next());
stat.execute("insert into test(value) values (1)", Statement.RETURN_GENERATED_KEYS);
rs = stat.getGeneratedKeys();
assertTrue(rs.next());
assertEquals(3, rs.getLong(1));
assertFalse(rs.next());
stat.execute("insert into test(value) values (1)", new int[0]);
assertFalse(stat.getGeneratedKeys().next());
stat.execute("insert into test(value) values (1)", new int[] { 1 });
rs = stat.getGeneratedKeys();
assertTrue(rs.next());
assertEquals(5, rs.getLong(1));
assertFalse(rs.next());
stat.execute("insert into test(value) values (1)", new String[0]);
assertFalse(stat.getGeneratedKeys().next());
stat.execute("insert into test(value) values (1)", new String[] { "ID" });
rs = stat.getGeneratedKeys();
assertTrue(rs.next());
assertEquals(7, rs.getLong(1));
assertFalse(rs.next());
prep = conn.prepareStatement("insert into test(value) values (1)");
prep.execute();
assertFalse(prep.getGeneratedKeys().next());
prep = conn.prepareStatement("insert into test(value) values (1)", Statement.NO_GENERATED_KEYS);
prep.execute();
assertFalse(prep.getGeneratedKeys().next());
prep = conn.prepareStatement("insert into test(value) values (1)", Statement.RETURN_GENERATED_KEYS);
prep.execute();
rs = prep.getGeneratedKeys();
assertTrue(rs.next());
assertEquals(10, rs.getLong(1));
assertFalse(rs.next());
prep = conn.prepareStatement("insert into test(value) values (1)", new int[0]);
prep.execute();
assertFalse(prep.getGeneratedKeys().next());
prep = conn.prepareStatement("insert into test(value) values (1)", new int[] { 1 });
prep.execute();
rs = prep.getGeneratedKeys();
assertTrue(rs.next());
assertEquals(12, rs.getLong(1));
assertFalse(rs.next());
prep = conn.prepareStatement("insert into test(value) values (1)", new String[0]);
prep.execute();
assertFalse(prep.getGeneratedKeys().next());
prep = conn.prepareStatement("insert into test(value) values (1)", new String[] { "ID" });
prep.execute();
rs = prep.getGeneratedKeys();
assertTrue(rs.next());
assertEquals(14, rs.getLong(1));
assertFalse(rs.next());
stat.execute("drop table test");
stat.execute("CREATE SEQUENCE SEQ");
stat.execute("CREATE TABLE TEST(ID INT)");
prep = conn.prepareStatement(
"INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)");
"INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)",
Statement.RETURN_GENERATED_KEYS);
prep.addBatch();
prep.addBatch();
prep.addBatch();
......
......@@ -573,12 +573,14 @@ public class TestResultSet extends TestBase {
ResultSet rs;
stat.execute("CREATE TABLE TEST(ID IDENTITY NOT NULL, NAME VARCHAR NULL)");
stat.execute("INSERT INTO TEST(NAME) VALUES('Hello')");
stat.execute("INSERT INTO TEST(NAME) VALUES('Hello')",
Statement.RETURN_GENERATED_KEYS);
rs = stat.getGeneratedKeys();
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
stat.execute("INSERT INTO TEST(NAME) VALUES('World')");
stat.execute("INSERT INTO TEST(NAME) VALUES('World')",
Statement.RETURN_GENERATED_KEYS);
rs = stat.getGeneratedKeys();
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
......
......@@ -351,16 +351,19 @@ public class TestStatement extends TestBase {
stat.execute("create table test1(id identity, x int)");
stat.execute("drop table if exists test2");
stat.execute("create table test2(id identity, x int)");
stat.execute("merge into test1(x) key(x) values(5)");
stat.execute("merge into test1(x) key(x) values(5)",
Statement.RETURN_GENERATED_KEYS);
ResultSet keys;
keys = stat.getGeneratedKeys();
keys.next();
assertEquals(1, keys.getInt(1));
stat.execute("insert into test2(x) values(10), (11), (12)");
stat.execute("merge into test1(x) key(x) values(5)");
stat.execute("merge into test1(x) key(x) values(5)",
Statement.RETURN_GENERATED_KEYS);
keys = stat.getGeneratedKeys();
assertFalse(keys.next());
stat.execute("merge into test1(x) key(x) values(6)");
stat.execute("merge into test1(x) key(x) values(6)",
Statement.RETURN_GENERATED_KEYS);
keys = stat.getGeneratedKeys();
keys.next();
assertEquals(2, keys.getInt(1));
......@@ -371,7 +374,8 @@ public class TestStatement extends TestBase {
Statement stat = conn.createStatement();
stat.execute("CREATE SEQUENCE SEQ");
stat.execute("CREATE TABLE TEST(ID INT)");
stat.execute("INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)");
stat.execute("INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)",
Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stat.getGeneratedKeys();
rs.next();
assertEquals(1, rs.getInt(1));
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论