Unverified 提交 47ed036f authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #858 from katzyn/generated_keys

Return all generated rows and columns from getGeneratedKeys()
......@@ -15,6 +15,7 @@ import org.h2.expression.ParameterInterface;
import org.h2.message.DbException;
import org.h2.message.Trace;
import org.h2.result.ResultInterface;
import org.h2.result.ResultWithGeneratedKeys;
import org.h2.util.MathUtils;
/**
......@@ -149,7 +150,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 +194,7 @@ public abstract class Command implements CommandInterface {
}
}
synchronized (sync) {
session.setCurrentCommand(this);
session.setCurrentCommand(this, false);
try {
while (true) {
database.checkPowerOff();
......@@ -238,7 +239,7 @@ public abstract class Command implements CommandInterface {
}
@Override
public int executeUpdate() {
public ResultWithGeneratedKeys executeUpdate(Object generatedKeysRequest) {
long start = 0;
Database database = session.getDatabase();
Object sync = database.isMultiThreaded() ? (Object) session : (Object) database;
......@@ -252,12 +253,17 @@ 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();
try {
return update();
int updateCount = update();
if (!Boolean.FALSE.equals(generatedKeysRequest)) {
return new ResultWithGeneratedKeys.WithKeys(updateCount,
session.getGeneratedKeys().getKeys(session));
}
return ResultWithGeneratedKeys.of(updateCount);
} catch (DbException e) {
start = filterConcurrentUpdate(e, start);
} catch (OutOfMemoryError e) {
......
......@@ -8,6 +8,7 @@ package org.h2.command;
import java.util.ArrayList;
import org.h2.expression.ParameterInterface;
import org.h2.result.ResultInterface;
import org.h2.result.ResultWithGeneratedKeys;
/**
* Represents a SQL statement.
......@@ -510,9 +511,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();
ResultWithGeneratedKeys 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).getUpdateCount();
executeRemaining();
return updateCount;
}
......
......@@ -9,6 +9,7 @@ import java.io.IOException;
import java.util.ArrayList;
import org.h2.engine.Constants;
import org.h2.engine.GeneratedKeysMode;
import org.h2.engine.SessionRemote;
import org.h2.engine.SysProperties;
import org.h2.expression.ParameterInterface;
......@@ -17,6 +18,7 @@ import org.h2.message.DbException;
import org.h2.message.Trace;
import org.h2.result.ResultInterface;
import org.h2.result.ResultRemote;
import org.h2.result.ResultWithGeneratedKeys;
import org.h2.util.New;
import org.h2.value.Transfer;
import org.h2.value.Value;
......@@ -194,10 +196,14 @@ public class CommandRemote implements CommandInterface {
}
@Override
public int executeUpdate() {
public ResultWithGeneratedKeys executeUpdate(Object generatedKeysRequest) {
checkParameters();
boolean supportsGeneratedKeys = session.isSupportsGeneratedKeys();
boolean readGeneratedKeys = supportsGeneratedKeys && !Boolean.FALSE.equals(generatedKeysRequest);
int objectId = readGeneratedKeys ? session.getNextId() : 0;
synchronized (session) {
int updateCount = 0;
ResultRemote generatedKeys = null;
boolean autoCommit = false;
for (int i = 0, count = 0; i < transferList.size(); i++) {
prepareIfRequired();
......@@ -206,9 +212,39 @@ public class CommandRemote implements CommandInterface {
session.traceOperation("COMMAND_EXECUTE_UPDATE", id);
transfer.writeInt(SessionRemote.COMMAND_EXECUTE_UPDATE).writeInt(id);
sendParameters(transfer);
if (supportsGeneratedKeys) {
int mode = GeneratedKeysMode.valueOf(generatedKeysRequest);
transfer.writeInt(mode);
switch (mode) {
case GeneratedKeysMode.COLUMN_NUMBERS: {
int[] keys = (int[]) generatedKeysRequest;
transfer.writeInt(keys.length);
for (int key : keys) {
transfer.writeInt(key);
}
break;
}
case GeneratedKeysMode.COLUMN_NAMES: {
String[] keys = (String[]) generatedKeysRequest;
transfer.writeInt(keys.length);
for (String key : keys) {
transfer.writeString(key);
}
break;
}
}
}
session.done(transfer);
updateCount = transfer.readInt();
autoCommit = transfer.readBoolean();
if (readGeneratedKeys) {
int columnCount = transfer.readInt();
if (generatedKeys != null) {
generatedKeys.close();
generatedKeys = null;
}
generatedKeys = new ResultRemote(session, transfer, objectId, columnCount, Integer.MAX_VALUE);
}
} catch (IOException e) {
session.removeServer(e, i--, ++count);
}
......@@ -216,7 +252,10 @@ public class CommandRemote implements CommandInterface {
session.setAutoCommitFromServer(autoCommit);
session.autoCommitIfCluster();
session.readSessionState();
return updateCount;
if (generatedKeys != null) {
return new ResultWithGeneratedKeys.WithKeys(updateCount, generatedKeys);
}
return ResultWithGeneratedKeys.of(updateCount);
}
}
......
......@@ -5667,6 +5667,10 @@ public class Parser {
readIfEqualOrTo();
read();
return new NoOperation(session);
} else if (readIf("SCOPE_GENERATED_KEYS")) {
readIfEqualOrTo();
read();
return new NoOperation(session);
} else if (readIf("SCHEMA")) {
readIfEqualOrTo();
Set command = new Set(session, SetTypes.SCHEMA);
......
......@@ -12,6 +12,7 @@ import org.h2.api.Trigger;
import org.h2.command.Command;
import org.h2.command.CommandInterface;
import org.h2.command.Prepared;
import org.h2.engine.GeneratedKeys;
import org.h2.engine.Right;
import org.h2.engine.Session;
import org.h2.engine.UndoLogRecord;
......@@ -20,6 +21,7 @@ import org.h2.expression.ConditionAndOr;
import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn;
import org.h2.expression.Parameter;
import org.h2.expression.SequenceValue;
import org.h2.index.Index;
import org.h2.message.DbException;
import org.h2.mvstore.db.MVPrimaryIndex;
......@@ -142,11 +144,14 @@ public class Insert extends Prepared implements ResultTarget {
setCurrentRowNumber(0);
table.fire(session, Trigger.INSERT, true);
rowNumber = 0;
GeneratedKeys generatedKeys = session.getGeneratedKeys();
generatedKeys.initialize(table);
int listSize = list.size();
if (listSize > 0) {
int columnLen = columns.length;
for (int x = 0; x < listSize; x++) {
session.startStatementWithinTransaction();
generatedKeys.nextRow();
Row newRow = table.getTemplateRow();
Expression[] expr = list.get(x);
setCurrentRowNumber(x + 1);
......@@ -160,6 +165,9 @@ public class Insert extends Prepared implements ResultTarget {
try {
Value v = c.convert(e.getValue(session), session.getDatabase().getMode());
newRow.setValue(index, v);
if (e instanceof SequenceValue) {
generatedKeys.add(c);
}
} catch (DbException ex) {
throw setRow(ex, x, getSQL(expr));
}
......@@ -179,6 +187,7 @@ public class Insert extends Prepared implements ResultTarget {
continue;
}
}
generatedKeys.confirmRow(newRow);
session.log(table, UndoLogRecord.INSERT, newRow);
table.fireAfterRow(session, null, newRow, false);
}
......@@ -190,8 +199,12 @@ public class Insert extends Prepared implements ResultTarget {
} else {
ResultInterface rows = query.query(0);
while (rows.next()) {
generatedKeys.nextRow();
Value[] r = rows.currentRow();
addRow(r);
Row newRow = addRowImpl(r);
if (newRow != null) {
generatedKeys.confirmRow(newRow);
}
}
rows.close();
}
......@@ -202,6 +215,10 @@ public class Insert extends Prepared implements ResultTarget {
@Override
public void addRow(Value[] values) {
addRowImpl(values);
}
private Row addRowImpl(Value[] values) {
Row newRow = table.getTemplateRow();
setCurrentRowNumber(++rowNumber);
for (int j = 0, len = columns.length; j < len; j++) {
......@@ -220,7 +237,9 @@ public class Insert extends Prepared implements ResultTarget {
table.addRow(session, newRow);
session.log(table, UndoLogRecord.INSERT, newRow);
table.fireAfterRow(session, null, newRow, false);
return newRow;
}
return null;
}
@Override
......
......@@ -11,11 +11,13 @@ import org.h2.api.Trigger;
import org.h2.command.Command;
import org.h2.command.CommandInterface;
import org.h2.command.Prepared;
import org.h2.engine.GeneratedKeys;
import org.h2.engine.Right;
import org.h2.engine.Session;
import org.h2.engine.UndoLogRecord;
import org.h2.expression.Expression;
import org.h2.expression.Parameter;
import org.h2.expression.SequenceValue;
import org.h2.index.Index;
import org.h2.message.DbException;
import org.h2.result.ResultInterface;
......@@ -84,11 +86,14 @@ public class Merge extends Prepared {
session.getUser().checkRight(targetTable, Right.INSERT);
session.getUser().checkRight(targetTable, Right.UPDATE);
setCurrentRowNumber(0);
GeneratedKeys generatedKeys = session.getGeneratedKeys();
if (!valuesExpressionList.isEmpty()) {
// process values in list
count = 0;
generatedKeys.initialize(targetTable);
for (int x = 0, size = valuesExpressionList.size(); x < size; x++) {
setCurrentRowNumber(x + 1);
generatedKeys.nextRow();
Expression[] expr = valuesExpressionList.get(x);
Row newRow = targetTable.getTemplateRow();
for (int i = 0, len = columns.length; i < len; i++) {
......@@ -100,6 +105,9 @@ public class Merge extends Prepared {
try {
Value v = c.convert(e.getValue(session));
newRow.setValue(index, v);
if (e instanceof SequenceValue) {
generatedKeys.add(c);
}
} catch (DbException ex) {
throw setRow(ex, count, getSQL(expr));
}
......@@ -116,6 +124,7 @@ public class Merge extends Prepared {
targetTable.lock(session, true, false);
while (rows.next()) {
count++;
generatedKeys.nextRow();
Value[] r = rows.currentRow();
Row newRow = targetTable.getTemplateRow();
setCurrentRowNumber(count);
......@@ -171,6 +180,7 @@ public class Merge extends Prepared {
if (!done) {
targetTable.lock(session, true, false);
targetTable.addRow(session, row);
session.getGeneratedKeys().confirmRow(row);
session.log(targetTable, UndoLogRecord.INSERT, row);
targetTable.fireAfterRow(session, null, row, false);
}
......
......@@ -96,7 +96,8 @@ public class ConnectionInfo implements Cloneable {
"CREATE", "CACHE_TYPE", "FILE_LOCK", "IGNORE_UNKNOWN_SETTINGS",
"IFEXISTS", "INIT", "PASSWORD", "RECOVER", "RECOVER_TEST",
"USER", "AUTO_SERVER", "AUTO_SERVER_PORT", "NO_UPGRADE",
"AUTO_RECONNECT", "OPEN_NEW", "PAGE_SIZE", "PASSWORD_HASH", "JMX" };
"AUTO_RECONNECT", "OPEN_NEW", "PAGE_SIZE", "PASSWORD_HASH", "JMX",
"SCOPE_GENERATED_KEYS" };
HashSet<String> set = new HashSet<>(list.size() + connectionTime.length);
set.addAll(list);
for (String key : connectionTime) {
......
......@@ -100,6 +100,21 @@ 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;
/**
* Minimum supported version of TCP protocol.
*/
public static final int TCP_PROTOCOL_VERSION_MIN_SUPPORTED = TCP_PROTOCOL_VERSION_6;
/**
* Maximum supported version of TCP protocol.
*/
public static final int TCP_PROTOCOL_VERSION_MAX_SUPPORTED = TCP_PROTOCOL_VERSION_17;
/**
* The major version of this database.
*/
......
......@@ -206,7 +206,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: \"" +
......@@ -224,7 +224,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();
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.engine;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn;
import org.h2.result.LocalResult;
import org.h2.result.Row;
import org.h2.table.Column;
import org.h2.table.Table;
import org.h2.util.New;
import org.h2.util.StringUtils;
import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* Class for gathering and processing of generated keys.
*/
public final class GeneratedKeys {
/**
* Data for result set with generated keys.
*/
private final ArrayList<Map<Column, Value>> data = New.arrayList();
/**
* Columns with generated keys in the current row.
*/
private final ArrayList<Column> row = 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;
/**
* Processed table.
*/
private Table table;
/**
* Remembers columns with generated keys.
*
* @param column
* table column
*/
public void add(Column column) {
if (Boolean.FALSE.equals(generatedKeysRequest)) {
return;
}
row.add(column);
}
/**
* 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) {
this.generatedKeysRequest = generatedKeysRequest;
data.clear();
row.clear();
allColumns.clear();
table = null;
}
/**
* Saves row with generated keys if any.
*
* @param tableRow
* table row that was inserted
*/
public void confirmRow(Row tableRow) {
if (Boolean.FALSE.equals(generatedKeysRequest)) {
return;
}
int size = row.size();
if (size > 0) {
if (size == 1) {
Column column = row.get(0);
data.add(Collections.singletonMap(column, tableRow.getValue(column.getColumnId())));
if (!allColumns.contains(column)) {
allColumns.add(column);
}
} else {
HashMap<Column, Value> map = new HashMap<>();
for (Column column : row) {
map.put(column, tableRow.getValue(column.getColumnId()));
if (!allColumns.contains(column)) {
allColumns.add(column);
}
}
data.add(map);
}
row.clear();
}
}
/**
* Returns generated keys.
*
* @return local result with generated keys
*/
public LocalResult getKeys(Session session) {
Database db = session == null ? null : session.getDatabase();
if (Boolean.FALSE.equals(generatedKeysRequest)) {
clear(null);
return new LocalResult();
}
ArrayList<ExpressionColumn> expressionColumns;
if (Boolean.TRUE.equals(generatedKeysRequest)) {
expressionColumns = new ArrayList<>(allColumns.size());
for (Column column : allColumns) {
expressionColumns.add(new ExpressionColumn(db, column));
}
} else if (generatedKeysRequest instanceof int[]) {
if (table != null) {
int[] indices = (int[]) generatedKeysRequest;
Column[] columns = table.getColumns();
int cnt = columns.length;
allColumns.clear();
expressionColumns = new ArrayList<>(indices.length);
for (int idx : indices) {
if (idx >= 1 && idx <= cnt) {
Column column = columns[idx - 1];
expressionColumns.add(new ExpressionColumn(db, column));
allColumns.add(column);
}
}
} else {
clear(null);
return new LocalResult();
}
} else if (generatedKeysRequest instanceof String[]) {
if (table != null) {
String[] names = (String[]) generatedKeysRequest;
allColumns.clear();
expressionColumns = new ArrayList<>(names.length);
for (String name : names) {
Column column;
search: if (table.doesColumnExist(name)) {
column = table.getColumn(name);
} else {
name = StringUtils.toUpperEnglish(name);
if (table.doesColumnExist(name)) {
column = table.getColumn(name);
} else {
for (Column c : table.getColumns()) {
if (c.getName().equalsIgnoreCase(name)) {
column = c;
break search;
}
}
continue;
}
}
expressionColumns.add(new ExpressionColumn(db, column));
allColumns.add(column);
}
} else {
clear(null);
return new LocalResult();
}
} else {
clear(null);
return new LocalResult();
}
int columnCount = expressionColumns.size();
if (columnCount == 0) {
clear(null);
return new LocalResult();
}
LocalResult result = new LocalResult(session, expressionColumns.toArray(new Expression[0]), columnCount);
for (Map<Column, Value> map : data) {
Value[] row = new Value[columnCount];
for (Map.Entry<Column, Value> entry : map.entrySet()) {
int idx = allColumns.indexOf(entry.getKey());
if (idx >= 0) {
row[idx] = entry.getValue();
}
}
for (int i = 0; i < columnCount; i++) {
if (row[i] == null) {
row[i] = ValueNull.INSTANCE;
}
}
result.addRow(row);
}
clear(null);
return result;
}
/**
* 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() {
row.clear();
}
@Override
public String toString() {
return allColumns + ": " + data.size();
}
}
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.engine;
import org.h2.api.ErrorCode;
import org.h2.message.DbException;
/**
* Modes of generated keys' gathering.
*/
public final class GeneratedKeysMode {
/**
* Generated keys are not needed.
*/
public static final int NONE = 0;
/**
* Generated keys should be configured automatically.
*/
public static final int AUTO = 1;
/**
* Use specified column indices to return generated keys from.
*/
public static final int COLUMN_NUMBERS = 2;
/**
* Use specified column names to return generated keys from.
*/
public static final int COLUMN_NAMES = 3;
/**
* Determines mode of generated keys' gathering.
*
* @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 mode for the specified generated keys request
*/
public static int valueOf(Object generatedKeysRequest) {
if (Boolean.FALSE.equals(generatedKeysRequest)) {
return NONE;
}
if (Boolean.TRUE.equals(generatedKeysRequest)) {
return AUTO;
}
if (generatedKeysRequest instanceof int[]) {
return COLUMN_NUMBERS;
}
if (generatedKeysRequest instanceof String[]) {
return COLUMN_NAMES;
}
throw DbException.get(ErrorCode.INVALID_VALUE_2,
generatedKeysRequest == null ? "null" : generatedKeysRequest.toString());
}
private GeneratedKeysMode() {
}
}
......@@ -85,6 +85,7 @@ public class Session extends SessionWithState {
private Value lastIdentity = ValueLong.get(0);
private Value lastScopeIdentity = ValueLong.get(0);
private Value lastTriggerIdentity;
private GeneratedKeys generatedKeys;
private int firstUncommittedLog = Session.LOG_WRITTEN;
private int firstUncommittedPos = Session.LOG_WRITTEN;
private HashMap<String, Savepoint> savepoints;
......@@ -1075,6 +1076,13 @@ public class Session extends SessionWithState {
return lastTriggerIdentity;
}
public GeneratedKeys getGeneratedKeys() {
if (generatedKeys == null) {
generatedKeys = new GeneratedKeys();
}
return generatedKeys;
}
/**
* Called when a log entry for this session is added. The session keeps
* track of the first entry in the transaction log that is not yet
......@@ -1237,9 +1245,20 @@ public class Session extends SessionWithState {
* executing the statement.
*
* @param command the command
*/
public void setCurrentCommand(Command command) {
* @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 setCurrentCommand(Command command, Object generatedKeysRequest) {
this.currentCommand = command;
// Preserve generated keys in case of a new query due to possible nested
// queries in update
if (command != null && !command.isQuery()) {
getGeneratedKeys().clear(generatedKeysRequest);
}
if (queryTimeout > 0 && command != null) {
currentCommandStart = System.currentTimeMillis();
long now = System.nanoTime();
......@@ -1790,4 +1809,10 @@ public class Session extends SessionWithState {
public void setColumnNamerConfiguration(ColumnNamerConfiguration columnNamerConfiguration) {
this.columnNamerConfiguration = columnNamerConfiguration;
}
@Override
public boolean isSupportsGeneratedKeys() {
return true;
}
}
......@@ -153,4 +153,13 @@ public interface SessionInterface extends Closeable {
* @return the current schema name
*/
String getCurrentSchemaName();
/**
* Returns is this session supports generated keys.
*
* @return {@code true} if generated keys are supported, {@code false} if only
* {@code SCOPE_IDENTITY()} is supported
*/
boolean isSupportsGeneratedKeys();
}
......@@ -117,8 +117,8 @@ public class SessionRemote extends SessionWithState implements DataHandler {
Transfer trans = new Transfer(this, socket);
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_MIN_SUPPORTED);
trans.writeInt(Constants.TCP_PROTOCOL_VERSION_MAX_SUPPORTED);
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);
}
/**
......@@ -869,4 +869,10 @@ public class SessionRemote extends SessionWithState implements DataHandler {
public void setCurrentSchemaName(String schema) {
throw DbException.getUnsupportedException("setSchema && remote session");
}
@Override
public boolean isSupportsGeneratedKeys() {
return getClientVersion() >= Constants.TCP_PROTOCOL_VERSION_17;
}
}
......@@ -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);
}
......
......@@ -94,6 +94,7 @@ public class JdbcConnection extends TraceObject
private Map<String, String> clientInfo;
private String mode;
private final boolean scopeGeneratedKeys;
/**
* INTERNAL
......@@ -132,6 +133,7 @@ public class JdbcConnection extends TraceObject
+ ", \"\");");
}
this.url = ci.getURL();
scopeGeneratedKeys = ci.getProperty("SCOPE_GENERATED_KEYS", false);
closeOld();
watcher = CloseWatcher.register(this, session, keepOpenStackTrace);
} catch (Exception e) {
......@@ -156,6 +158,7 @@ public class JdbcConnection extends TraceObject
this.getQueryTimeout = clone.getQueryTimeout;
this.getReadOnly = clone.getReadOnly;
this.rollback = clone.rollback;
this.scopeGeneratedKeys = clone.scopeGeneratedKeys;
this.watcher = null;
if (clone.clientInfo != null) {
this.clientInfo = new HashMap<>(clone.clientInfo);
......@@ -172,6 +175,7 @@ public class JdbcConnection extends TraceObject
setTrace(trace, TraceObject.CONNECTION, id);
this.user = user;
this.url = url;
this.scopeGeneratedKeys = false;
this.watcher = null;
}
......@@ -299,7 +303,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);
}
......@@ -325,7 +329,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);
}
......@@ -490,7 +494,7 @@ public class JdbcConnection extends TraceObject
checkClosedForWrite();
try {
commit = prepareCommand("COMMIT", commit);
commit.executeUpdate();
commit.executeUpdate(false);
} finally {
afterWriting();
}
......@@ -688,7 +692,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);
}
......@@ -743,7 +747,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);
}
......@@ -760,7 +764,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);
......@@ -1016,7 +1020,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++;
......@@ -1044,7 +1048,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;
......@@ -1130,19 +1134,20 @@ 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);
}
}
/**
* Creates a new prepared statement. This method just calls
* prepareStatement(String sql) internally. The method getGeneratedKeys only
* supports one column.
* Creates a new prepared statement.
*
* @param sql the SQL statement
* @param autoGeneratedKeys ignored
* @param autoGeneratedKeys
* {@link Statement#RETURN_GENERATED_KEYS} if generated keys should
* be available for retrieval, {@link Statement#NO_GENERATED_KEYS} if
* generated keys should not be available
* @return the prepared statement
* @throws SQLException if the connection is closed
*/
......@@ -1150,23 +1155,31 @@ 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);
}
}
/**
* Creates a new prepared statement. This method just calls
* prepareStatement(String sql) internally. The method getGeneratedKeys only
* supports one column.
* Creates a new prepared statement.
*
* @param sql the SQL statement
* @param columnIndexes ignored
* @param columnIndexes
* an array of column indexes indicating the columns with generated
* keys that should be returned from the inserted row
* @return the prepared statement
* @throws SQLException if the connection is closed
*/
......@@ -1174,23 +1187,30 @@ 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);
}
}
/**
* Creates a new prepared statement. This method just calls
* prepareStatement(String sql) internally. The method getGeneratedKeys only
* supports one column.
* Creates a new prepared statement.
*
* @param sql the SQL statement
* @param columnNames ignored
* @param columnNames
* an array of column names indicating the columns with generated
* keys that should be returned from the inserted row
* @return the prepared statement
* @throws SQLException if the connection is closed
*/
......@@ -1198,11 +1218,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);
}
......@@ -1529,7 +1556,7 @@ public class JdbcConnection extends TraceObject
private void rollbackInternal() {
rollback = prepareCommand("ROLLBACK", rollback);
rollback.executeUpdate();
rollback.executeUpdate(false);
}
/**
......@@ -1556,6 +1583,13 @@ public class JdbcConnection extends TraceObject
executingStatement = stat;
}
/**
* INTERNAL
*/
boolean scopeGeneratedKeys() {
return scopeGeneratedKeys;
}
/**
* INTERNAL
*/
......
......@@ -31,9 +31,10 @@ import org.h2.expression.ParameterInterface;
import org.h2.message.DbException;
import org.h2.message.TraceObject;
import org.h2.result.ResultInterface;
import org.h2.tools.SimpleResultSet;
import org.h2.result.ResultWithGeneratedKeys;
import org.h2.util.DateTimeUtils;
import org.h2.util.IOUtils;
import org.h2.util.MergedResultSet;
import org.h2.util.New;
import org.h2.value.DataType;
import org.h2.value.Value;
......@@ -61,13 +62,15 @@ public class JdbcPreparedStatement extends JdbcStatement implements
protected CommandInterface command;
private final String sqlStatement;
private ArrayList<Value[]> batchParameters;
private ArrayList<Object> batchIdentities;
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 = conn.scopeGeneratedKeys() ? false : generatedKeysRequest;
setTrace(session.getTrace(), TraceObject.PREPARED_STATEMENT, id);
this.sqlStatement = sql;
command = conn.prepareCommand(sql, fetchSize);
......@@ -193,7 +196,14 @@ public class JdbcPreparedStatement extends JdbcStatement implements
synchronized (session) {
try {
setExecutingStatement(command);
updateCount = command.executeUpdate();
ResultWithGeneratedKeys result = command.executeUpdate(generatedKeysRequest);
updateCount = result.getUpdateCount();
ResultInterface gk = result.getGeneratedKeys();
if (gk != null) {
int id = getNextId(TraceObject.RESULT_SET);
generatedKeys = new JdbcResultSet(conn, this, command, gk, id,
false, true, false);
}
} finally {
setExecutingStatement(null);
}
......@@ -236,7 +246,13 @@ public class JdbcPreparedStatement extends JdbcStatement implements
updatable, cachedColumnLabelMap);
} else {
returnsResultSet = false;
updateCount = command.executeUpdate();
ResultWithGeneratedKeys result = command.executeUpdate(generatedKeysRequest);
updateCount = result.getUpdateCount();
ResultInterface gk = result.getGeneratedKeys();
if (gk != null) {
generatedKeys = new JdbcResultSet(conn, this, command, gk, id,
false, true, false);
}
}
} finally {
if (!lazy) {
......@@ -1243,7 +1259,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements
// set
batchParameters = New.arrayList();
}
batchIdentities = New.arrayList();
batchIdentities = new MergedResultSet();
int size = batchParameters.size();
int[] result = new int[size];
boolean error = false;
......@@ -1261,10 +1277,9 @@ public class JdbcPreparedStatement extends JdbcStatement implements
}
try {
result[i] = executeUpdateInternal();
ResultSet rs = conn.getGeneratedKeys(this, id);
while (rs.next()) {
batchIdentities.add(rs.getObject(1));
}
// Cannot use own implementation, it returns batch identities
ResultSet rs = super.getGeneratedKeys();
batchIdentities.add(rs);
} catch (Exception re) {
SQLException e = logAndConvert(re);
if (next == null) {
......@@ -1293,14 +1308,8 @@ public class JdbcPreparedStatement extends JdbcStatement implements
@Override
public ResultSet getGeneratedKeys() throws SQLException {
if (batchIdentities != null && !batchIdentities.isEmpty()) {
SimpleResultSet rs = new SimpleResultSet();
rs.addColumn("identity", java.sql.Types.INTEGER,
10, 0);
for (Object o : batchIdentities) {
rs.addRow(o);
}
return rs;
if (batchIdentities != null) {
return batchIdentities.getResult();
}
return super.getGeneratedKeys();
}
......
......@@ -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() {
......
......@@ -18,6 +18,8 @@ import org.h2.engine.SysProperties;
import org.h2.message.DbException;
import org.h2.message.TraceObject;
import org.h2.result.ResultInterface;
import org.h2.result.ResultWithGeneratedKeys;
import org.h2.tools.SimpleResultSet;
import org.h2.util.New;
import org.h2.util.ParserUtil;
import org.h2.util.StringUtils;
......@@ -33,6 +35,7 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
protected int maxRows;
protected int fetchSize = SysProperties.SERVER_RESULT_SET_FETCH_SIZE;
protected int updateCount;
protected JdbcResultSet generatedKeys;
protected final int resultSetType;
protected final int resultSetConcurrency;
protected final boolean closedByResultSet;
......@@ -120,7 +123,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 +151,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 +166,15 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
synchronized (session) {
setExecutingStatement(command);
try {
updateCount = command.executeUpdate();
ResultWithGeneratedKeys result = command.executeUpdate(
conn.scopeGeneratedKeys() ? false : generatedKeysRequest);
updateCount = result.getUpdateCount();
ResultInterface gk = result.getGeneratedKeys();
if (gk != null) {
int id = getNextId(TraceObject.RESULT_SET);
generatedKeys = new JdbcResultSet(conn, this, command, gk, id,
false, true, false);
}
} finally {
setExecutingStatement(null);
}
......@@ -191,13 +202,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 +230,14 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
closedByResultSet, scrollable, updatable);
} else {
returnsResultSet = false;
updateCount = command.executeUpdate();
ResultWithGeneratedKeys result = command.executeUpdate(
conn.scopeGeneratedKeys() ? false : generatedKeysRequest);
updateCount = result.getUpdateCount();
ResultInterface gk = result.getGeneratedKeys();
if (gk != null) {
generatedKeys = new JdbcResultSet(conn, this, command, gk, id,
false, true, false);
}
}
} finally {
if (!lazy) {
......@@ -756,7 +774,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) {
......@@ -816,6 +834,15 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
debugCodeAssign("ResultSet", TraceObject.RESULT_SET, id, "getGeneratedKeys()");
}
checkClosed();
if (!conn.scopeGeneratedKeys()) {
if (generatedKeys != null) {
return generatedKeys;
}
if (session.isSupportsGeneratedKeys()) {
return new SimpleResultSet();
}
}
// Compatibility mode or an old server, so use SCOPE_IDENTITY()
return conn.getGeneratedKeys(this, id);
} catch (Exception e) {
throw logAndConvert(e);
......@@ -876,11 +903,12 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
/**
* Executes a statement and returns the update count.
* This method just calls executeUpdate(String sql) internally.
* The method getGeneratedKeys supports at most one columns and row.
*
* @param sql the SQL statement
* @param autoGeneratedKeys ignored
* @param autoGeneratedKeys
* {@link Statement.RETURN_GENERATED_KEYS} if generated keys should
* be available for retrieval, {@link Statement.NO_GENERATED_KEYS} if
* generated keys should not be available
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
......@@ -894,7 +922,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);
}
......@@ -902,11 +930,12 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
/**
* Executes a statement and returns the update count.
* This method just calls executeUpdate(String sql) internally.
* The method getGeneratedKeys supports at most one columns and row.
*
* @param sql the SQL statement
* @param autoGeneratedKeys ignored
* @param autoGeneratedKeys
* {@link Statement.RETURN_GENERATED_KEYS} if generated keys should
* be available for retrieval, {@link Statement.NO_GENERATED_KEYS} if
* generated keys should not be available
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
......@@ -919,7 +948,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);
}
......@@ -927,11 +956,11 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
/**
* Executes a statement and returns the update count.
* This method just calls executeUpdate(String sql) internally.
* The method getGeneratedKeys supports at most one columns and row.
*
* @param sql the SQL statement
* @param columnIndexes ignored
* @param columnIndexes
* an array of column indexes indicating the columns with generated
* keys that should be returned from the inserted row
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
......@@ -944,7 +973,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);
}
......@@ -952,11 +981,11 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
/**
* Executes a statement and returns the update count.
* This method just calls executeUpdate(String sql) internally.
* The method getGeneratedKeys supports at most one columns and row.
*
* @param sql the SQL statement
* @param columnIndexes ignored
* @param columnIndexes
* an array of column indexes indicating the columns with generated
* keys that should be returned from the inserted row
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
......@@ -969,7 +998,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);
}
......@@ -977,11 +1006,11 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
/**
* Executes a statement and returns the update count.
* This method just calls executeUpdate(String sql) internally.
* The method getGeneratedKeys supports at most one columns and row.
*
* @param sql the SQL statement
* @param columnNames ignored
* @param columnNames
* an array of column names indicating the columns with generated
* keys that should be returned from the inserted row
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
......@@ -994,7 +1023,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);
}
......@@ -1002,11 +1031,11 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
/**
* Executes a statement and returns the update count.
* This method just calls executeUpdate(String sql) internally.
* The method getGeneratedKeys supports at most one columns and row.
*
* @param sql the SQL statement
* @param columnNames ignored
* @param columnNames
* an array of column names indicating the columns with generated
* keys that should be returned from the inserted row
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
......@@ -1019,7 +1048,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);
}
......@@ -1027,11 +1056,12 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
/**
* Executes a statement and returns the update count.
* This method just calls execute(String sql) internally.
* The method getGeneratedKeys supports at most one columns and row.
*
* @param sql the SQL statement
* @param autoGeneratedKeys ignored
* @param autoGeneratedKeys
* {@link Statement.RETURN_GENERATED_KEYS} if generated keys should
* be available for retrieval, {@link Statement.NO_GENERATED_KEYS} if
* generated keys should not be available
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
......@@ -1044,7 +1074,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);
}
......@@ -1052,11 +1082,11 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
/**
* Executes a statement and returns the update count.
* This method just calls execute(String sql) internally.
* The method getGeneratedKeys supports at most one columns and row.
*
* @param sql the SQL statement
* @param columnIndexes ignored
* @param columnIndexes
* an array of column indexes indicating the columns with generated
* keys that should be returned from the inserted row
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
......@@ -1069,7 +1099,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);
}
......@@ -1077,11 +1107,11 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
/**
* Executes a statement and returns the update count.
* This method just calls execute(String sql) internally.
* The method getGeneratedKeys supports at most one columns and row.
*
* @param sql the SQL statement
* @param columnNames ignored
* @param columnNames
* an array of column names indicating the columns with generated
* keys that should be returned from the inserted row
* @return the update count (number of row affected by an insert,
* update or delete, or 0 if no rows or the statement was a
* create, drop, commit or rollback)
......@@ -1094,7 +1124,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);
}
......@@ -1197,11 +1227,15 @@ public class JdbcStatement extends TraceObject implements Statement, JdbcStateme
if (resultSet != null) {
resultSet.closeInternal();
}
if (generatedKeys != null) {
generatedKeys.closeInternal();
}
}
} finally {
cancelled = false;
resultSet = null;
updateCount = -1;
generatedKeys = null;
}
}
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.result;
/**
* Result of update command with optional generated keys.
*/
public class ResultWithGeneratedKeys {
/**
* Result of update command with generated keys;
*/
public static final class WithKeys extends ResultWithGeneratedKeys {
private final ResultInterface generatedKeys;
/**
* Creates a result with update count and generated keys.
*
* @param updateCount
* update count
* @param generatedKeys
* generated keys
*/
public WithKeys(int updateCount, ResultInterface generatedKeys) {
super(updateCount);
this.generatedKeys = generatedKeys;
}
@Override
public ResultInterface getGeneratedKeys() {
return generatedKeys;
}
}
/**
* Returns a result with only update count.
*
* @param updateCount
* update count
*/
public static ResultWithGeneratedKeys of(int updateCount) {
return new ResultWithGeneratedKeys(updateCount);
}
private final int updateCount;
ResultWithGeneratedKeys(int updateCount) {
this.updateCount = updateCount;
}
/**
* Returns generated keys, or {@code null}.
*
* @return generated keys, or {@code null}
*/
public ResultInterface getGeneratedKeys() {
return null;
}
/**
* Returns update count.
*
* @return update count
*/
public int getUpdateCount() {
return updateCount;
}
}
......@@ -203,6 +203,7 @@ public class TriggerObject extends SchemaObjectBase {
* times for each statement.
*
* @param session the session
* @param table the table
* @param oldRow the old row
* @param newRow the new row
* @param beforeAction true if this method is called before the operation is
......@@ -210,7 +211,7 @@ public class TriggerObject extends SchemaObjectBase {
* @param rollback when the operation occurred within a rollback
* @return true if no further action is required (for 'instead of' triggers)
*/
public boolean fireRow(Session session, Row oldRow, Row newRow,
public boolean fireRow(Session session, Table table, Row oldRow, Row newRow,
boolean beforeAction, boolean rollback) {
if (!rowBased || before != beforeAction) {
return false;
......@@ -260,6 +261,7 @@ public class TriggerObject extends SchemaObjectBase {
Object o = newList[i];
if (o != newListBackup[i]) {
Value v = DataType.convertToValue(session, o, Value.UNKNOWN);
session.getGeneratedKeys().add(table.getColumn(i));
newRow.setValue(i, v);
}
}
......
......@@ -21,6 +21,7 @@ import org.h2.command.Command;
import org.h2.engine.ConnectionInfo;
import org.h2.engine.Constants;
import org.h2.engine.Engine;
import org.h2.engine.GeneratedKeysMode;
import org.h2.engine.Session;
import org.h2.engine.SessionRemote;
import org.h2.engine.SysProperties;
......@@ -31,6 +32,7 @@ import org.h2.jdbc.JdbcSQLException;
import org.h2.message.DbException;
import org.h2.result.ResultColumn;
import org.h2.result.ResultInterface;
import org.h2.result.ResultWithGeneratedKeys;
import org.h2.store.LobStorageInterface;
import org.h2.util.IOUtils;
import org.h2.util.SmallLRUCache;
......@@ -88,15 +90,15 @@ public class TcpServerThread implements Runnable {
}
int minClientVersion = transfer.readInt();
int maxClientVersion = transfer.readInt();
if (maxClientVersion < Constants.TCP_PROTOCOL_VERSION_6) {
if (maxClientVersion < Constants.TCP_PROTOCOL_VERSION_MIN_SUPPORTED) {
throw DbException.get(ErrorCode.DRIVER_VERSION_ERROR_2,
"" + clientVersion, "" + Constants.TCP_PROTOCOL_VERSION_6);
} else if (minClientVersion > Constants.TCP_PROTOCOL_VERSION_16) {
"" + clientVersion, "" + Constants.TCP_PROTOCOL_VERSION_MIN_SUPPORTED);
} else if (minClientVersion > Constants.TCP_PROTOCOL_VERSION_MAX_SUPPORTED) {
throw DbException.get(ErrorCode.DRIVER_VERSION_ERROR_2,
"" + clientVersion, "" + Constants.TCP_PROTOCOL_VERSION_16);
"" + clientVersion, "" + Constants.TCP_PROTOCOL_VERSION_MAX_SUPPORTED);
}
if (maxClientVersion >= Constants.TCP_PROTOCOL_VERSION_16) {
clientVersion = Constants.TCP_PROTOCOL_VERSION_16;
if (maxClientVersion >= Constants.TCP_PROTOCOL_VERSION_MAX_SUPPORTED) {
clientVersion = Constants.TCP_PROTOCOL_VERSION_MAX_SUPPORTED;
} else {
clientVersion = maxClientVersion;
}
......@@ -178,7 +180,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 +304,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 +355,48 @@ public class TcpServerThread implements Runnable {
int id = transfer.readInt();
Command command = (Command) cache.getObject(id, false);
setParameters(command);
boolean supportsGeneratedKeys = clientVersion >= Constants.TCP_PROTOCOL_VERSION_17;
boolean writeGeneratedKeys = supportsGeneratedKeys;
Object generatedKeysRequest;
if (supportsGeneratedKeys) {
int mode = transfer.readInt();
switch (mode) {
case GeneratedKeysMode.NONE:
generatedKeysRequest = false;
writeGeneratedKeys = false;
break;
case GeneratedKeysMode.AUTO:
generatedKeysRequest = true;
break;
case GeneratedKeysMode.COLUMN_NUMBERS: {
int len = transfer.readInt();
int[] keys = new int[len];
for (int i = 0; i < len; i++) {
keys[i] = transfer.readInt();
}
generatedKeysRequest = keys;
break;
}
case GeneratedKeysMode.COLUMN_NAMES: {
int len = transfer.readInt();
String[] keys = new String[len];
for (int i = 0; i < len; i++) {
keys[i] = transfer.readString();
}
generatedKeysRequest = keys;
break;
}
default:
throw DbException.get(ErrorCode.CONNECTION_BROKEN_1,
"Unsupported generated keys' mode " + mode);
}
} else {
generatedKeysRequest = false;
}
int old = session.getModificationId();
int updateCount;
ResultWithGeneratedKeys result;
synchronized (session) {
updateCount = command.executeUpdate();
result = command.executeUpdate(generatedKeysRequest);
}
int status;
if (session.isClosed()) {
......@@ -365,8 +405,22 @@ public class TcpServerThread implements Runnable {
} else {
status = getState(old);
}
transfer.writeInt(status).writeInt(updateCount).
transfer.writeInt(status).writeInt(result.getUpdateCount()).
writeBoolean(session.getAutoCommit());
if (writeGeneratedKeys) {
ResultInterface generatedKeys = result.getGeneratedKeys();
int columnCount = generatedKeys.getVisibleColumnCount();
transfer.writeInt(columnCount);
int rowCount = generatedKeys.getRowCount();
transfer.writeInt(rowCount);
for (int i = 0; i < columnCount; i++) {
ResultColumn.writeColumn(transfer, generatedKeys, i);
}
for (int i = 0; i < rowCount; i++) {
sendRow(generatedKeys);
}
generatedKeys.close();
}
transfer.flush();
break;
}
......
......@@ -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 {
......
......@@ -210,8 +210,8 @@ public class FileLock implements Runnable {
Constants.DEFAULT_TCP_PORT, false);
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_MIN_SUPPORTED);
transfer.writeInt(Constants.TCP_PROTOCOL_VERSION_MAX_SUPPORTED);
transfer.writeString(null);
transfer.writeString(null);
transfer.writeString(id);
......
......@@ -321,6 +321,7 @@ public class Column {
value = ValueNull.INSTANCE;
} else {
value = localDefaultExpression.getValue(session).convertTo(type);
session.getGeneratedKeys().add(this);
if (primaryKey) {
session.setLastIdentity(value);
}
......@@ -330,6 +331,7 @@ public class Column {
if (value == ValueNull.INSTANCE) {
if (convertNullToDefault) {
value = localDefaultExpression.getValue(session).convertTo(type);
session.getGeneratedKeys().add(this);
}
if (value == ValueNull.INSTANCE && !nullable) {
if (mode.convertInsertNullToZero) {
......
......@@ -1026,7 +1026,7 @@ public abstract class Table extends SchemaObjectBase {
boolean beforeAction, boolean rollback) {
if (triggers != null) {
for (TriggerObject trigger : triggers) {
boolean done = trigger.fireRow(session, oldRow, newRow, beforeAction, rollback);
boolean done = trigger.fireRow(session, this, oldRow, newRow, beforeAction, rollback);
if (done) {
return true;
}
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.util;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.h2.tools.SimpleResultSet;
/**
* Merged result set. Used to combine several result sets into one. Merged
* result set will contain rows from all appended result sets. Result sets are
* not required to have the same lists of columns, but required to have
* compatible column definitions, for example, if one result set has a
* {@link java.sql.Types#VARCHAR} column {@code NAME} then another results sets
* that have {@code NAME} column should also define it with the same type.
*/
public final class MergedResultSet {
/**
* Metadata of a column.
*/
private static final class ColumnInfo {
final String name;
final int type;
final int precision;
final int scale;
/**
* Creates metadata.
*
* @param name
* name of the column
* @param type
* type of the column, see {@link java.sql.Types}
* @param precision
* precision of the column
* @param scale
* scale of the column
*/
ColumnInfo(String name, int type, int precision, int scale) {
this.name = name;
this.type = type;
this.precision = precision;
this.scale = scale;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
ColumnInfo other = (ColumnInfo) obj;
return name.equals(other.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
}
private final ArrayList<Map<ColumnInfo, Object>> data = New.arrayList();
private final ArrayList<ColumnInfo> columns = New.arrayList();
/**
* Appends a result set.
*
* @param rs
* result set to append
* @throws SQLException
* on SQL exception
*/
public void add(ResultSet rs) throws SQLException {
ResultSetMetaData meta = rs.getMetaData();
int cols = meta.getColumnCount();
if (cols == 0) {
return;
}
ColumnInfo[] info = new ColumnInfo[cols];
for (int i = 1; i <= cols; i++) {
ColumnInfo ci = new ColumnInfo(meta.getColumnName(i), meta.getColumnType(i), meta.getPrecision(i),
meta.getScale(i));
info[i - 1] = ci;
if (!columns.contains(ci)) {
columns.add(ci);
}
}
while (rs.next()) {
if (cols == 1) {
data.add(Collections.singletonMap(info[0], rs.getObject(1)));
} else {
HashMap<ColumnInfo, Object> map = new HashMap<>();
for (int i = 1; i <= cols; i++) {
ColumnInfo ci = info[i - 1];
map.put(ci, rs.getObject(i));
}
data.add(map);
}
}
}
/**
* Returns merged results set.
*
* @return result set with rows from all appended result sets
*/
public SimpleResultSet getResult() {
SimpleResultSet rs = new SimpleResultSet();
for (ColumnInfo ci : columns) {
rs.addColumn(ci.name, ci.type, ci.precision, ci.scale);
}
for (Map<ColumnInfo, Object> map : data) {
Object[] row = new Object[columns.size()];
for (Map.Entry<ColumnInfo, Object> entry : map.entrySet()) {
row[columns.indexOf(entry.getKey())] = entry.getValue();
}
rs.addRow(row);
}
return rs;
}
@Override
public String toString() {
return columns + ": " + data.size();
}
}
......@@ -97,6 +97,7 @@ import org.h2.test.jdbc.TestConnection;
import org.h2.test.jdbc.TestCustomDataTypesHandler;
import org.h2.test.jdbc.TestDatabaseEventListener;
import org.h2.test.jdbc.TestDriver;
import org.h2.test.jdbc.TestGetGeneratedKeys;
import org.h2.test.jdbc.TestJavaObject;
import org.h2.test.jdbc.TestJavaObjectSerializer;
import org.h2.test.jdbc.TestLimitUpdates;
......@@ -814,6 +815,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest(new TestPreparedStatement());
addTest(new TestResultSet());
addTest(new TestStatement());
addTest(new TestGetGeneratedKeys());
addTest(new TestTransactionIsolation());
addTest(new TestUpdatableResultSet());
addTest(new TestZloty());
......
......@@ -227,7 +227,7 @@ public class TestTriggersConstraints extends TestBase implements Trigger {
assertEquals(1, count);
ResultSet gkRs;
gkRs = pstat.getGeneratedKeys();
gkRs = stat.executeQuery("select scope_identity()");
assertTrue(gkRs.next());
assertEquals(1, gkRs.getInt(1));
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.UUID;
import org.h2.api.Trigger;
import org.h2.jdbc.JdbcPreparedStatement;
import org.h2.jdbc.JdbcStatement;
import org.h2.test.TestBase;
/**
* Tests for the {@link Statement#getGeneratedKeys()}.
*/
public class TestGetGeneratedKeys extends TestBase {
public static class TestGetGeneratedKeysTrigger implements Trigger {
@Override
public void close() throws SQLException {
}
@Override
public void fire(Connection conn, Object[] oldRow, Object[] newRow) throws SQLException {
if (newRow[0] == null) {
newRow[0] = UUID.randomUUID();
}
}
@Override
public void init(Connection conn, String schemaName, String triggerName, String tableName, boolean before,
int type) throws SQLException {
}
@Override
public void remove() throws SQLException {
}
}
/**
* Run just this test.
*
* @param a
* ignored
*/
public static void main(String... a) throws Exception {
TestBase.createCaller().init().test();
}
@Override
public void test() throws Exception {
deleteDb("getGeneratedKeys");
Connection conn = getConnection("getGeneratedKeys");
testBatchAndMergeInto(conn);
testCalledSequenses(conn);
testInsertWithSelect(conn);
testMergeUsing(conn);
testMultithreaded(conn);
testNameCase(conn);
testPrepareStatement_Execute(conn);
testPrepareStatement_ExecuteBatch(conn);
testPrepareStatement_ExecuteLargeBatch(conn);
testPrepareStatement_ExecuteLargeUpdate(conn);
testPrepareStatement_ExecuteUpdate(conn);
testPrepareStatement_int_Execute(conn);
testPrepareStatement_int_ExecuteBatch(conn);
testPrepareStatement_int_ExecuteLargeBatch(conn);
testPrepareStatement_int_ExecuteLargeUpdate(conn);
testPrepareStatement_int_ExecuteUpdate(conn);
testPrepareStatement_intArray_Execute(conn);
testPrepareStatement_intArray_ExecuteBatch(conn);
testPrepareStatement_intArray_ExecuteLargeBatch(conn);
testPrepareStatement_intArray_ExecuteLargeUpdate(conn);
testPrepareStatement_intArray_ExecuteUpdate(conn);
testPrepareStatement_StringArray_Execute(conn);
testPrepareStatement_StringArray_ExecuteBatch(conn);
testPrepareStatement_StringArray_ExecuteLargeBatch(conn);
testPrepareStatement_StringArray_ExecuteLargeUpdate(conn);
testPrepareStatement_StringArray_ExecuteUpdate(conn);
testStatementExecute(conn);
testStatementExecute_int(conn);
testStatementExecute_intArray(conn);
testStatementExecute_StringArray(conn);
testStatementExecuteLargeUpdate(conn);
testStatementExecuteLargeUpdate_int(conn);
testStatementExecuteLargeUpdate_intArray(conn);
testStatementExecuteLargeUpdate_StringArray(conn);
testStatementExecuteUpdate(conn);
testStatementExecuteUpdate_int(conn);
testStatementExecuteUpdate_intArray(conn);
testStatementExecuteUpdate_StringArray(conn);
testTrigger(conn);
conn.close();
deleteDb("getGeneratedKeys");
}
/**
* Test for batch updates and MERGE INTO operator.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testBatchAndMergeInto(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST(ID BIGINT AUTO_INCREMENT, UID UUID DEFAULT RANDOM_UUID(), VALUE INT)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (?), (?)",
Statement.RETURN_GENERATED_KEYS);
prep.setInt(1, 1);
prep.setInt(2, 2);
prep.addBatch();
prep.setInt(1, 3);
prep.setInt(1, 4);
prep.addBatch();
prep.executeBatch();
ResultSet rs = prep.getGeneratedKeys();
rs.next();
assertEquals(1L, rs.getLong(1));
UUID u1 = (UUID) rs.getObject(2);
assertTrue(u1 != null);
rs.next();
assertEquals(2L, rs.getLong(1));
UUID u2 = (UUID) rs.getObject(2);
assertTrue(u2 != null);
rs.next();
assertEquals(3L, rs.getLong(1));
UUID u3 = (UUID) rs.getObject(2);
assertTrue(u3 != null);
rs.next();
assertEquals(4L, rs.getLong(1));
UUID u4 = (UUID) rs.getObject(2);
assertTrue(u4 != null);
assertFalse(rs.next());
assertFalse(u1.equals(u2));
assertFalse(u2.equals(u3));
assertFalse(u3.equals(u4));
prep = conn.prepareStatement("MERGE INTO TEST(ID, VALUE) KEY(ID) VALUES (?, ?)",
Statement.RETURN_GENERATED_KEYS);
prep.setInt(1, 2);
prep.setInt(2, 10);
prep.execute();
rs = prep.getGeneratedKeys();
assertFalse(rs.next());
prep.setInt(1, 5);
prep.executeUpdate();
rs = prep.getGeneratedKeys();
rs.next();
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
stat.execute("DROP TABLE TEST");
}
/**
* Test for keys generated by sequences.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testCalledSequenses(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE SEQUENCE SEQ");
stat.execute("CREATE TABLE TEST(ID INT)");
PreparedStatement prep;
prep = conn.prepareStatement("INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)", Statement.RETURN_GENERATED_KEYS);
prep.execute();
ResultSet rs = prep.getGeneratedKeys();
rs.next();
assertEquals(1, rs.getInt(1));
assertFalse(rs.next());
prep = conn.prepareStatement("INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)", Statement.RETURN_GENERATED_KEYS);
prep.execute();
rs = prep.getGeneratedKeys();
rs.next();
assertEquals(2, rs.getInt(1));
assertFalse(rs.next());
prep = conn.prepareStatement("INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)", new int[] { 1 });
prep.execute();
rs = prep.getGeneratedKeys();
rs.next();
assertEquals(3, rs.getInt(1));
assertFalse(rs.next());
prep = conn.prepareStatement("INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)", new String[] { "ID" });
prep.execute();
rs = prep.getGeneratedKeys();
rs.next();
assertEquals(4, rs.getInt(1));
assertFalse(rs.next());
prep = conn.prepareStatement("INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)", ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
prep.execute();
rs = prep.getGeneratedKeys();
rs.next();
assertFalse(rs.next());
stat.execute("DROP TABLE TEST");
stat.execute("DROP SEQUENCE SEQ");
stat.execute("CREATE TABLE TEST(ID BIGINT)");
stat.execute("CREATE SEQUENCE SEQ");
prep = conn.prepareStatement("INSERT INTO TEST VALUES (30), (NEXT VALUE FOR SEQ),"
+ " (NEXT VALUE FOR SEQ), (NEXT VALUE FOR SEQ), (20)", Statement.RETURN_GENERATED_KEYS);
prep.executeUpdate();
rs = prep.getGeneratedKeys();
rs.next();
assertEquals(1L, rs.getLong(1));
rs.next();
assertEquals(2L, rs.getLong(1));
rs.next();
assertEquals(3L, rs.getLong(1));
assertFalse(rs.next());
stat.execute("DROP TABLE TEST");
stat.execute("DROP SEQUENCE SEQ");
}
/**
* Test method for INSERT ... SELECT operator.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testInsertWithSelect(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT, VALUE INT NOT NULL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) SELECT 10",
Statement.RETURN_GENERATED_KEYS);
prep.executeUpdate();
ResultSet rs = prep.getGeneratedKeys();
assertTrue(rs.next());
assertEquals(1, rs.getLong(1));
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for MERGE USING operator.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testMergeUsing(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE SOURCE (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ " UID INT NOT NULL UNIQUE, VALUE INT NOT NULL)");
stat.execute("CREATE TABLE DESTINATION (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ " UID INT NOT NULL UNIQUE, VALUE INT NOT NULL)");
PreparedStatement ps = conn.prepareStatement("INSERT INTO SOURCE(UID, VALUE) VALUES (?, ?)");
for (int i = 1; i <= 100; i++) {
ps.setInt(1, i);
ps.setInt(2, i * 10 + 5);
ps.executeUpdate();
}
// Insert first half of a rows with different values
ps = conn.prepareStatement("INSERT INTO DESTINATION(UID, VALUE) VALUES (?, ?)");
for (int i = 1; i <= 50; i++) {
ps.setInt(1, i);
ps.setInt(2, i * 10);
ps.executeUpdate();
}
// And merge second half into it, first half will be updated with a new values
ps = conn.prepareStatement(
"MERGE INTO DESTINATION USING SOURCE ON (DESTINATION.UID = SOURCE.UID)"
+ " WHEN MATCHED THEN UPDATE SET VALUE = SOURCE.VALUE"
+ " WHEN NOT MATCHED THEN INSERT (UID, VALUE) VALUES (SOURCE.UID, SOURCE.VALUE)",
Statement.RETURN_GENERATED_KEYS);
// All rows should be either updated or inserted
assertEquals(100, ps.executeUpdate());
ResultSet rs = ps.getGeneratedKeys();
// Only 50 keys for inserted rows should be generated
for (int i = 1; i <= 50; i++) {
assertTrue(rs.next());
assertEquals(i + 50, rs.getLong(1));
}
assertFalse(rs.next());
rs.close();
// Check merged data
rs = stat.executeQuery("SELECT ID, UID, VALUE FROM DESTINATION ORDER BY ID");
for (int i = 1; i <= 100; i++) {
assertTrue(rs.next());
assertEquals(i, rs.getLong(1));
assertEquals(i, rs.getInt(2));
assertEquals(i * 10 + 5, rs.getInt(3));
}
assertFalse(rs.next());
stat.execute("DROP TABLE SOURCE");
stat.execute("DROP TABLE DESTINATION");
}
/**
* Test method for shared connection between several statements in different
* threads.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testMultithreaded(final Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT," + "VALUE INT NOT NULL)");
final int count = 4, iterations = 10_000;
Thread[] threads = new Thread[count];
final long[] keys = new long[count * iterations];
for (int i = 0; i < count; i++) {
final int num = i;
threads[num] = new Thread("getGeneratedKeys-" + num) {
@Override
public void run() {
try {
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (?)",
Statement.RETURN_GENERATED_KEYS);
for (int i = 0; i < iterations; i++) {
int value = iterations * num + i;
prep.setInt(1, value);
prep.execute();
ResultSet rs = prep.getGeneratedKeys();
rs.next();
keys[value] = rs.getLong(1);
rs.close();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
};
}
for (int i = 0; i < count; i++) {
threads[i].start();
}
for (int i = 0; i < count; i++) {
threads[i].join();
}
ResultSet rs = stat.executeQuery("SELECT VALUE, ID FROM TEST ORDER BY VALUE");
for (int i = 0; i < keys.length; i++) {
assertTrue(rs.next());
assertEquals(i, rs.getInt(1));
assertEquals(keys[i], rs.getLong(2));
}
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for case of letters in column names.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testNameCase(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "\"id\" UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
// Test columns with only difference in case
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)",
new String[] { "id", "ID" });
prep.executeUpdate();
ResultSet rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("id", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(1L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
// Test lower case name of upper case column
stat.execute("ALTER TABLE TEST DROP COLUMN \"id\"");
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)", new String[] { "id" });
prep.executeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertFalse(rs.next());
rs.close();
// Test upper case name of lower case column
stat.execute("ALTER TABLE TEST ALTER COLUMN ID RENAME TO \"id\"");
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (30)", new String[] { "ID" });
prep.executeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("id", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String)}.{@link PreparedStatement#execute()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_Execute(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)");
prep.execute();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String)}.{@link PreparedStatement#executeBatch()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_ExecuteBatch(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)");
prep.addBatch();
prep.addBatch();
prep.executeBatch();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String)}.{@link PreparedStatement#executeLargeBatch()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_ExecuteLargeBatch(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
JdbcPreparedStatement prep = (JdbcPreparedStatement) conn
.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)");
prep.addBatch();
prep.addBatch();
prep.executeLargeBatch();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String)}.{@link PreparedStatement#executeLargeUpdate()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_ExecuteLargeUpdate(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
JdbcPreparedStatement prep = (JdbcPreparedStatement) conn
.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)");
prep.executeLargeUpdate();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String)}.{@link PreparedStatement#executeUpdate()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_ExecuteUpdate(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)");
prep.executeUpdate();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, int)}.{@link PreparedStatement#execute()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_int_Execute(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)",
Statement.NO_GENERATED_KEYS);
prep.execute();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)", Statement.RETURN_GENERATED_KEYS);
prep.execute();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, int)}.{@link PreparedStatement#executeBatch()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_int_ExecuteBatch(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)",
Statement.NO_GENERATED_KEYS);
prep.addBatch();
prep.addBatch();
prep.executeBatch();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)", Statement.RETURN_GENERATED_KEYS);
prep.addBatch();
prep.addBatch();
prep.executeBatch();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertTrue(rs.next());
assertEquals(4L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, int)}.{@link PreparedStatement#executeLargeBatch()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_int_ExecuteLargeBatch(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
JdbcPreparedStatement prep = (JdbcPreparedStatement) conn
.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)", Statement.NO_GENERATED_KEYS);
prep.addBatch();
prep.addBatch();
prep.executeLargeBatch();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)",
Statement.RETURN_GENERATED_KEYS);
prep.addBatch();
prep.addBatch();
prep.executeLargeBatch();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertTrue(rs.next());
assertEquals(4L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, int)}.{@link PreparedStatement#executeLargeUpdate()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_int_ExecuteLargeUpdate(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
JdbcPreparedStatement prep = (JdbcPreparedStatement) conn
.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)", Statement.NO_GENERATED_KEYS);
prep.executeLargeUpdate();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)",
Statement.RETURN_GENERATED_KEYS);
prep.executeLargeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, int)}.{@link PreparedStatement#executeUpdate()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_int_ExecuteUpdate(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)",
Statement.NO_GENERATED_KEYS);
prep.executeUpdate();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)", Statement.RETURN_GENERATED_KEYS);
prep.executeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, int[])}.{@link PreparedStatement#execute()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_intArray_Execute(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)", new int[0]);
prep.execute();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)", new int[] { 1, 2 });
prep.execute();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (30)", new int[] { 2, 1 });
prep.execute();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(3L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (40)", new int[] { 2 });
prep.execute();
rs = prep.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, int[])}.{@link PreparedStatement#executeBatch()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_intArray_ExecuteBatch(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)", new int[0]);
prep.addBatch();
prep.addBatch();
prep.executeBatch();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)", new int[] { 1, 2 });
prep.addBatch();
prep.addBatch();
prep.executeBatch();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertTrue(rs.next());
assertEquals(4L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (30)", new int[] { 2, 1 });
prep.addBatch();
prep.addBatch();
prep.executeBatch();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(5L, rs.getLong(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(6L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (40)", new int[] { 2 });
prep.addBatch();
prep.addBatch();
prep.executeBatch();
rs = prep.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, int[])}.{@link PreparedStatement#executeLargeBatch()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_intArray_ExecuteLargeBatch(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
JdbcPreparedStatement prep = (JdbcPreparedStatement) conn
.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)", new int[0]);
prep.addBatch();
prep.addBatch();
prep.executeLargeBatch();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)", new int[] { 1, 2 });
prep.addBatch();
prep.addBatch();
prep.executeLargeBatch();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertTrue(rs.next());
assertEquals(4L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (30)", new int[] { 2, 1 });
prep.addBatch();
prep.addBatch();
prep.executeLargeBatch();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(5L, rs.getLong(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(6L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (40)", new int[] { 2 });
prep.addBatch();
prep.addBatch();
prep.executeLargeBatch();
rs = prep.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, int[])}.{@link PreparedStatement#executeLargeUpdate()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_intArray_ExecuteLargeUpdate(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
JdbcPreparedStatement prep = (JdbcPreparedStatement) conn
.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)", new int[0]);
prep.executeLargeUpdate();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)", new int[] { 1, 2 });
prep.executeLargeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (30)", new int[] { 2, 1 });
prep.executeLargeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(3L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (40)", new int[] { 2 });
prep.executeLargeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, int[])}.{@link PreparedStatement#executeUpdate()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_intArray_ExecuteUpdate(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)", new int[0]);
prep.executeUpdate();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)", new int[] { 1, 2 });
prep.executeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (30)", new int[] { 2, 1 });
prep.executeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(3L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (40)", new int[] { 2 });
prep.executeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, String[])}.{@link PreparedStatement#execute()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_StringArray_Execute(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)", new String[0]);
prep.executeUpdate();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)", new String[] { "ID", "UID" });
prep.execute();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (30)", new String[] { "UID", "ID" });
prep.execute();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(3L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (40)", new String[] { "UID" });
prep.execute();
rs = prep.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, String[])}.{@link PreparedStatement#executeBatch()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_StringArray_ExecuteBatch(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)", new String[0]);
prep.addBatch();
prep.addBatch();
prep.executeBatch();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)", new String[] { "ID", "UID" });
prep.addBatch();
prep.addBatch();
prep.executeBatch();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertTrue(rs.next());
assertEquals(4L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (30)", new String[] { "UID", "ID" });
prep.addBatch();
prep.addBatch();
prep.executeBatch();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(5L, rs.getLong(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(6L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (40)", new String[] { "UID" });
prep.addBatch();
prep.addBatch();
prep.executeBatch();
rs = prep.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, String[])}.{@link PreparedStatement#executeLargeBatch()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_StringArray_ExecuteLargeBatch(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
JdbcPreparedStatement prep = (JdbcPreparedStatement) conn
.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)", new String[0]);
prep.addBatch();
prep.addBatch();
prep.executeLargeBatch();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)",
new String[] { "ID", "UID" });
prep.addBatch();
prep.addBatch();
prep.executeLargeBatch();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertTrue(rs.next());
assertEquals(4L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (30)",
new String[] { "UID", "ID" });
prep.addBatch();
prep.addBatch();
prep.executeLargeBatch();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(5L, rs.getLong(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(6L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (40)",
new String[] { "UID" });
prep.addBatch();
prep.addBatch();
prep.executeLargeBatch();
rs = prep.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, String[])}.{@link PreparedStatement#executeLargeUpdate()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_StringArray_ExecuteLargeUpdate(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
JdbcPreparedStatement prep = (JdbcPreparedStatement) conn
.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)", new String[0]);
prep.executeLargeUpdate();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)",
new String[] { "ID", "UID" });
prep.executeLargeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (30)",
new String[] { "UID", "ID" });
prep.executeLargeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(3L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
prep = (JdbcPreparedStatement) conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (40)",
new String[] { "UID" });
prep.executeLargeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for
* {@link Connection#prepareStatement(String, String[])}.{@link PreparedStatement#executeUpdate()}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testPrepareStatement_StringArray_ExecuteUpdate(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
PreparedStatement prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (10)", new String[0]);
prep.executeUpdate();
ResultSet rs = prep.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (20)", new String[] { "ID", "UID" });
prep.executeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (30)", new String[] { "UID", "ID" });
prep.executeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(3L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
prep = conn.prepareStatement("INSERT INTO TEST(VALUE) VALUES (40)", new String[] { "UID" });
prep.executeUpdate();
rs = prep.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for {@link Statement#execute(String)}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testStatementExecute(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
stat.execute("INSERT INTO TEST(VALUE) VALUES (10)");
ResultSet rs = stat.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for {@link Statement#execute(String, int)}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testStatementExecute_int(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
stat.execute("INSERT INTO TEST(VALUE) VALUES (10)", Statement.NO_GENERATED_KEYS);
ResultSet rs = stat.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.execute("INSERT INTO TEST(VALUE) VALUES (20)", Statement.RETURN_GENERATED_KEYS);
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for {@link Statement#execute(String, int[])}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testStatementExecute_intArray(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
stat.execute("INSERT INTO TEST(VALUE) VALUES (10)", new int[0]);
ResultSet rs = stat.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.execute("INSERT INTO TEST(VALUE) VALUES (20)", new int[] { 1, 2 });
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("INSERT INTO TEST(VALUE) VALUES (30)", new int[] { 2, 1 });
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(3L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
stat.execute("INSERT INTO TEST(VALUE) VALUES (40)", new int[] { 2 });
rs = stat.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for {@link Statement#executeUpdate(String, String[])}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testStatementExecute_StringArray(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
stat.execute("INSERT INTO TEST(VALUE) VALUES (10)", new String[0]);
ResultSet rs = stat.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.execute("INSERT INTO TEST(VALUE) VALUES (20)", new String[] { "ID", "UID" });
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("INSERT INTO TEST(VALUE) VALUES (30)", new String[] { "UID", "ID" });
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(3L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
stat.execute("INSERT INTO TEST(VALUE) VALUES (40)", new String[] { "UID" });
rs = stat.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for {@link Statement#executeLargeUpdate(String)}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testStatementExecuteLargeUpdate(Connection conn) throws Exception {
JdbcStatement stat = (JdbcStatement) conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
stat.executeLargeUpdate("INSERT INTO TEST(VALUE) VALUES (10)");
ResultSet rs = stat.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for {@link Statement#executeLargeUpdate(String, int)}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testStatementExecuteLargeUpdate_int(Connection conn) throws Exception {
JdbcStatement stat = (JdbcStatement) conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
stat.executeLargeUpdate("INSERT INTO TEST(VALUE) VALUES (10)", Statement.NO_GENERATED_KEYS);
ResultSet rs = stat.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.executeLargeUpdate("INSERT INTO TEST(VALUE) VALUES (20)", Statement.RETURN_GENERATED_KEYS);
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for {@link Statement#executeLargeUpdate(String, int[])}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testStatementExecuteLargeUpdate_intArray(Connection conn) throws Exception {
JdbcStatement stat = (JdbcStatement) conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
stat.executeLargeUpdate("INSERT INTO TEST(VALUE) VALUES (10)", new int[0]);
ResultSet rs = stat.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.executeLargeUpdate("INSERT INTO TEST(VALUE) VALUES (20)", new int[] { 1, 2 });
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.executeLargeUpdate("INSERT INTO TEST(VALUE) VALUES (30)", new int[] { 2, 1 });
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(3L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
stat.executeLargeUpdate("INSERT INTO TEST(VALUE) VALUES (40)", new int[] { 2 });
rs = stat.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for {@link Statement#executeLargeUpdate(String, String[])}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testStatementExecuteLargeUpdate_StringArray(Connection conn) throws Exception {
JdbcStatement stat = (JdbcStatement) conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
stat.executeLargeUpdate("INSERT INTO TEST(VALUE) VALUES (10)", new String[0]);
ResultSet rs = stat.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.executeLargeUpdate("INSERT INTO TEST(VALUE) VALUES (20)", new String[] { "ID", "UID" });
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.executeLargeUpdate("INSERT INTO TEST(VALUE) VALUES (30)", new String[] { "UID", "ID" });
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(3L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
stat.executeLargeUpdate("INSERT INTO TEST(VALUE) VALUES (40)", new String[] { "UID" });
rs = stat.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for {@link Statement#executeUpdate(String)}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testStatementExecuteUpdate(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
stat.executeUpdate("INSERT INTO TEST(VALUE) VALUES (10)");
ResultSet rs = stat.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for {@link Statement#executeUpdate(String, int)}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testStatementExecuteUpdate_int(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
stat.executeUpdate("INSERT INTO TEST(VALUE) VALUES (10)", Statement.NO_GENERATED_KEYS);
ResultSet rs = stat.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.executeUpdate("INSERT INTO TEST(VALUE) VALUES (20)", Statement.RETURN_GENERATED_KEYS);
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for {@link Statement#executeUpdate(String, int[])}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testStatementExecuteUpdate_intArray(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
stat.executeUpdate("INSERT INTO TEST(VALUE) VALUES (10)", new int[0]);
ResultSet rs = stat.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.executeUpdate("INSERT INTO TEST(VALUE) VALUES (20)", new int[] { 1, 2 });
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.executeUpdate("INSERT INTO TEST(VALUE) VALUES (30)", new int[] { 2, 1 });
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(3L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
stat.executeUpdate("INSERT INTO TEST(VALUE) VALUES (40)", new int[] { 2 });
rs = stat.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test method for {@link Statement#executeUpdate(String, String[])}.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testStatementExecuteUpdate_StringArray(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST (ID BIGINT PRIMARY KEY AUTO_INCREMENT,"
+ "UID UUID NOT NULL DEFAULT RANDOM_UUID(), VALUE INT NOT NULL)");
stat.executeUpdate("INSERT INTO TEST(VALUE) VALUES (10)", new String[0]);
ResultSet rs = stat.getGeneratedKeys();
assertFalse(rs.next());
rs.close();
stat.executeUpdate("INSERT INTO TEST(VALUE) VALUES (20)", new String[] { "ID", "UID" });
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("ID", rs.getMetaData().getColumnName(1));
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(2L, rs.getLong(1));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertFalse(rs.next());
rs.close();
stat.executeUpdate("INSERT INTO TEST(VALUE) VALUES (30)", new String[] { "UID", "ID" });
rs = stat.getGeneratedKeys();
assertEquals(2, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertEquals("ID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertEquals(3L, rs.getLong(2));
assertFalse(rs.next());
rs.close();
stat.executeUpdate("INSERT INTO TEST(VALUE) VALUES (40)", new String[] { "UID" });
rs = stat.getGeneratedKeys();
assertEquals(1, rs.getMetaData().getColumnCount());
assertEquals("UID", rs.getMetaData().getColumnName(1));
assertTrue(rs.next());
assertEquals(UUID.class, rs.getObject(1).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
}
/**
* Test for keys generated by trigger.
*
* @param conn
* connection
* @throws Exception
* on exception
*/
private void testTrigger(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST(ID UUID, VALUE INT)");
stat.execute("CREATE TRIGGER TEST_INSERT BEFORE INSERT ON TEST FOR EACH ROW CALL \""
+ TestGetGeneratedKeysTrigger.class.getName() + '"');
stat.executeUpdate("INSERT INTO TEST(VALUE) VALUES (10), (20)", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stat.getGeneratedKeys();
rs.next();
UUID u1 = (UUID) rs.getObject(1);
rs.next();
UUID u2 = (UUID) rs.getObject(1);
assertFalse(rs.next());
rs = stat.executeQuery("SELECT ID FROM TEST ORDER BY VALUE");
rs.next();
assertEquals(u1, rs.getObject(1));
rs.next();
assertEquals(u2, rs.getObject(1));
stat.execute("DROP TRIGGER TEST_INSERT");
stat.execute("DROP TABLE TEST");
}
}
......@@ -27,6 +27,7 @@ import java.sql.Types;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.UUID;
import org.h2.api.ErrorCode;
import org.h2.api.Trigger;
import org.h2.engine.SysProperties;
......@@ -83,15 +84,12 @@ public class TestPreparedStatement extends TestBase {
testOffsetDateTime8(conn);
testInstant8(conn);
testArray(conn);
testUUIDGeneratedKeys(conn);
testSetObject(conn);
testPreparedSubquery(conn);
testLikeIndex(conn);
testCasewhen(conn);
testSubquery(conn);
testObject(conn);
testIdentity(conn);
testBatchGeneratedKeys(conn);
testDataTypes(conn);
testGetMoreResults(conn);
testBlob(conn);
......@@ -521,21 +519,6 @@ public class TestPreparedStatement extends TestBase {
stat.execute("drop table test_uuid");
}
private void testUUIDGeneratedKeys(Connection conn) throws SQLException {
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE TEST_UUID(id UUID DEFAULT " +
"random_UUID() PRIMARY KEY)");
stat.execute("INSERT INTO TEST_UUID() VALUES()");
ResultSet rs = stat.getGeneratedKeys();
rs.next();
byte[] data = rs.getBytes(1);
assertEquals(16, data.length);
stat.execute("INSERT INTO TEST_UUID VALUES(random_UUID())");
rs = stat.getGeneratedKeys();
assertFalse(rs.next());
stat.execute("DROP TABLE TEST_UUID");
}
/**
* A trigger that creates a sequence value.
*/
......@@ -572,12 +555,17 @@ 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
assertEquals(1, rs.getLong(1));
stat.execute("insert into test values(100)");
rs = stat.getGeneratedKeys();
// No generated keys
assertFalse(rs.next());
// Value from sequence from trigger
rs = stat.executeQuery("select scope_identity()");
rs.next();
assertEquals(100, rs.getLong(1));
stat.execute("drop sequence seq");
......@@ -1263,83 +1251,6 @@ public class TestPreparedStatement extends TestBase {
}
private void testIdentity(Connection conn) throws SQLException {
Statement stat = conn.createStatement();
stat.execute("CREATE SEQUENCE SEQ");
stat.execute("CREATE TABLE TEST(ID INT)");
PreparedStatement prep;
prep = conn.prepareStatement(
"INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)");
prep.execute();
ResultSet rs = prep.getGeneratedKeys();
rs.next();
assertEquals(1, rs.getInt(1));
assertFalse(rs.next());
prep = conn.prepareStatement(
"INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)",
Statement.RETURN_GENERATED_KEYS);
prep.execute();
rs = prep.getGeneratedKeys();
rs.next();
assertEquals(2, rs.getInt(1));
assertFalse(rs.next());
prep = conn.prepareStatement(
"INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)",
new int[] { 1 });
prep.execute();
rs = prep.getGeneratedKeys();
rs.next();
assertEquals(3, rs.getInt(1));
assertFalse(rs.next());
prep = conn.prepareStatement(
"INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)",
new String[] { "ID" });
prep.execute();
rs = prep.getGeneratedKeys();
rs.next();
assertEquals(4, rs.getInt(1));
assertFalse(rs.next());
prep = conn.prepareStatement(
"INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)",
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
prep.execute();
rs = prep.getGeneratedKeys();
rs.next();
assertEquals(5, rs.getInt(1));
assertFalse(rs.next());
stat.execute("DROP TABLE TEST");
stat.execute("DROP SEQUENCE SEQ");
}
private void testBatchGeneratedKeys(Connection conn) throws SQLException {
Statement stat = conn.createStatement();
stat.execute("CREATE SEQUENCE SEQ");
stat.execute("CREATE TABLE TEST(ID INT)");
PreparedStatement prep = conn.prepareStatement(
"INSERT INTO TEST VALUES(NEXT VALUE FOR SEQ)");
prep.addBatch();
prep.addBatch();
prep.addBatch();
prep.executeBatch();
ResultSet keys = prep.getGeneratedKeys();
keys.next();
assertEquals(1, keys.getLong(1));
keys.next();
assertEquals(2, keys.getLong(1));
keys.next();
assertEquals(3, keys.getLong(1));
assertFalse(keys.next());
stat.execute("DROP TABLE TEST");
stat.execute("DROP SEQUENCE SEQ");
}
private int getLength() {
return getSize(LOB_SIZE, LOB_SIZE_BIG);
}
......
......@@ -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));
......
......@@ -447,7 +447,7 @@ public class TestWeb extends TestBase {
assertContains(result, "There is currently no running statement");
result = client.get(url,
"query.do?sql=@generated insert into test(id) values(test_sequence.nextval)");
assertContains(result, "SCOPE_IDENTITY()");
assertContains(result, "<tr><th>ID</th></tr><tr><td>1</td></tr>");
result = client.get(url, "query.do?sql=@maxrows 2000");
assertContains(result, "Max rowcount is set");
result = client.get(url, "query.do?sql=@password_hash user password");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论