use of org.teiid.translator.TranslatorBatchException in project teiid by teiid.
the class JDBCUpdateExecution method execute.
public int[] execute(BatchedUpdates batchedCommand) throws TranslatorException {
boolean succeeded = false;
boolean commitType = false;
if (batchedCommand.isSingleResult()) {
commitType = getAutoCommit(null);
}
Command[] commands = batchedCommand.getUpdateCommands().toArray(new Command[batchedCommand.getUpdateCommands().size()]);
result = new int[commands.length];
TranslatedCommand tCommand = null;
int batchStart = 0;
int i = 0;
try {
// before at the end of the command execution.
if (commitType) {
connection.setAutoCommit(false);
}
List<TranslatedCommand> executedCmds = new ArrayList<TranslatedCommand>();
TranslatedCommand previousCommand = null;
for (; i < commands.length; i++) {
tCommand = translateCommand(commands[i]);
if (tCommand.isPrepared()) {
PreparedStatement pstmt = null;
if (previousCommand != null && previousCommand.isPrepared() && previousCommand.getSql().equals(tCommand.getSql())) {
pstmt = (PreparedStatement) statement;
} else {
if (!executedCmds.isEmpty()) {
executeBatch(i, result, executedCmds);
batchStart = i;
}
pstmt = getPreparedStatement(tCommand.getSql());
}
bind(pstmt, tCommand.getPreparedValues(), null);
pstmt.addBatch();
} else {
if (previousCommand != null && previousCommand.isPrepared()) {
executeBatch(i, result, executedCmds);
batchStart = i;
getStatement();
}
if (statement == null) {
getStatement();
}
statement.addBatch(tCommand.getSql());
}
executedCmds.add(tCommand);
previousCommand = tCommand;
}
if (!executedCmds.isEmpty()) {
executeBatch(commands.length, result, executedCmds);
}
succeeded = true;
} catch (TranslatorException e) {
if (batchedCommand.isSingleResult()) {
throw e;
}
int size = i + 1;
// if there is a BatchUpdateException, there are more update counts to accumulate
if (e.getCause() instanceof BatchUpdateException) {
BatchUpdateException bue = (BatchUpdateException) e.getCause();
int[] batchResults = bue.getUpdateCounts();
for (int j = 0; j < batchResults.length; j++) {
result[batchStart + j] = batchResults[j];
}
size = batchStart + batchResults.length;
} else {
size = batchStart;
}
// resize the result and throw exception
throw new TranslatorBatchException(e, Arrays.copyOf(result, size));
} catch (SQLException e) {
if (batchedCommand.isSingleResult()) {
throw new JDBCExecutionException(JDBCPlugin.Event.TEIID11011, e, tCommand);
}
// resize the result and throw exception
throw new TranslatorBatchException(e, Arrays.copyOf(result, batchStart));
} finally {
if (commitType) {
restoreAutoCommit(!succeeded, null);
}
}
return result;
}
use of org.teiid.translator.TranslatorBatchException in project teiid by teiid.
the class JDBCUpdateExecution method executeTranslatedCommand.
/**
* @param translatedComm
* @throws TranslatorException
* @since 4.3
*/
private void executeTranslatedCommand(TranslatedCommand translatedComm) throws TranslatorException {
// create statement or PreparedStatement and execute
String sql = translatedComm.getSql();
boolean commitType = false;
boolean succeeded = false;
try {
int updateCount = 0;
Class<?>[] keyColumnDataTypes = null;
String[] keyColumnNames = null;
if (command instanceof Insert && context.getCommandContext().isReturnAutoGeneratedKeys() && executionFactory.supportsGeneratedKeys(context, command)) {
Insert insert = (Insert) command;
NamedTable nt = insert.getTable();
if (nt.getMetadataObject() != null) {
KeyRecord key = nt.getMetadataObject().getPrimaryKey();
if (key != null) {
List<Column> cols = key.getColumns();
keyColumnDataTypes = new Class<?>[cols.size()];
keyColumnNames = new String[cols.size()];
for (int i = 0; i < cols.size(); i++) {
Column c = cols.get(i);
keyColumnDataTypes[i] = c.getJavaType();
// won't work in scenarios where the teiid name is changed or contains a .
keyColumnNames[i] = c.getName();
}
}
}
}
if (!translatedComm.isPrepared()) {
statement = getStatement();
// handle autoGeneratedKeys
if (keyColumnDataTypes != null) {
if (executionFactory.useColumnNamesForGeneratedKeys()) {
updateCount = statement.executeUpdate(sql, keyColumnNames);
} else {
updateCount = statement.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
}
} else {
updateCount = statement.executeUpdate(sql);
}
result = new int[] { updateCount };
addStatementWarnings();
} else {
PreparedStatement pstatement = null;
if (statement != null) {
statement.close();
}
if (keyColumnDataTypes != null) {
if (executionFactory.useColumnNamesForGeneratedKeys()) {
pstatement = connection.prepareStatement(sql, keyColumnNames);
} else {
pstatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
}
} else {
pstatement = getPreparedStatement(sql);
}
statement = pstatement;
Iterator<? extends List<?>> vi = null;
if (command instanceof BulkCommand) {
BulkCommand batchCommand = (BulkCommand) command;
vi = batchCommand.getParameterValues();
}
int k = 0;
int batchStart = 0;
if (vi != null) {
try {
commitType = getAutoCommit(translatedComm);
if (commitType) {
connection.setAutoCommit(false);
}
int maxBatchSize = (command instanceof Insert) ? maxPreparedInsertBatchSize : Integer.MAX_VALUE;
boolean done = false;
outer: while (!done) {
for (int i = 0; i < maxBatchSize; i++) {
if (vi.hasNext()) {
List<?> values = vi.next();
bind(pstatement, translatedComm.getPreparedValues(), values);
k++;
} else {
if (i == 0) {
break outer;
}
done = true;
break;
}
}
int[] results = pstatement.executeBatch();
batchStart = k;
if (result == null) {
result = results;
} else {
int len = result.length;
result = Arrays.copyOf(result, len + results.length);
System.arraycopy(results, 0, result, len, results.length);
}
}
} catch (SQLException e) {
int size = k + 1;
if (result == null) {
result = new int[size];
} else {
result = Arrays.copyOf(result, size);
}
// if there is a BatchUpdateException, there are more update counts to accumulate
if (e instanceof BatchUpdateException) {
BatchUpdateException bue = (BatchUpdateException) e;
int[] batchResults = bue.getUpdateCounts();
for (int j = 0; j < batchResults.length; j++) {
result[batchStart + j] = batchResults[j];
}
size = batchStart + batchResults.length;
} else {
size = batchStart;
}
// resize the result and throw exception
throw new TranslatorBatchException(e, Arrays.copyOf(result, size));
}
} else {
bind(pstatement, translatedComm.getPreparedValues(), null);
updateCount = pstatement.executeUpdate();
result = new int[] { updateCount };
}
addStatementWarnings();
succeeded = true;
}
if (keyColumnDataTypes != null) {
try {
ResultSet keys = statement.getGeneratedKeys();
GeneratedKeys generatedKeys = context.getCommandContext().returnGeneratedKeys(keyColumnNames, keyColumnDataTypes);
// many databases only support returning a single generated value, but we'll still attempt to gather all
outer: while (keys.next()) {
List<Object> vals = new ArrayList<Object>(keyColumnDataTypes.length);
for (int i = 0; i < keyColumnDataTypes.length; i++) {
Object value = this.executionFactory.retrieveValue(keys, i + 1, keyColumnDataTypes[i]);
if (value != null && TypeFacility.getRuntimeType(value.getClass()) != keyColumnDataTypes[i]) {
// TODO we may need to let the engine to the final conversion
LogManager.logDetail(LogConstants.CTX_CONNECTOR, JDBCPlugin.Util.gs(JDBCPlugin.Event.TEIID11023, keyColumnDataTypes[i], keyColumnNames[i], value.getClass()));
continue outer;
}
vals.add(value);
}
generatedKeys.addKey(vals);
}
} catch (SQLException e) {
context.addWarning(e);
// $NON-NLS-1$
LogManager.logDetail(LogConstants.CTX_CONNECTOR, e, "Exception determining generated keys, no keys will be returned");
}
}
} catch (SQLException err) {
throw new JDBCExecutionException(JDBCPlugin.Event.TEIID11013, err, translatedComm);
} finally {
if (commitType) {
restoreAutoCommit(!succeeded, translatedComm);
}
}
}
use of org.teiid.translator.TranslatorBatchException in project teiid by teiid.
the class TestJDBCUpdateExecution method testPreparedBatchedUpdateFailed.
@Test
public void testPreparedBatchedUpdateFailed() throws Exception {
// $NON-NLS-1$
Insert command = (Insert) TranslationHelper.helpTranslate(TranslationHelper.BQT_VDB, "insert into BQT1.SmallA (IntKey) values (1)");
Parameter param = new Parameter();
param.setType(DataTypeManager.DefaultDataClasses.INTEGER);
param.setValueIndex(0);
List<Expression> values = ((ExpressionValueSource) command.getValueSource()).getValues();
values.set(0, param);
command.setParameterValues(Arrays.asList(Arrays.asList(1), Arrays.asList(1)).iterator());
Connection connection = Mockito.mock(Connection.class);
PreparedStatement s = Mockito.mock(PreparedStatement.class);
Mockito.stub(s.executeBatch()).toThrow(new BatchUpdateException(new int[] { 1, Statement.EXECUTE_FAILED }));
Mockito.stub(connection.prepareStatement("INSERT INTO SmallA (IntKey) VALUES (?)")).toReturn(s);
JDBCExecutionFactory config = new JDBCExecutionFactory();
ResultSet r = Mockito.mock(ResultSet.class);
ResultSetMetaData rs = Mockito.mock(ResultSetMetaData.class);
Mockito.stub(r.getMetaData()).toReturn(rs);
FakeExecutionContextImpl context = new FakeExecutionContextImpl();
JDBCUpdateExecution updateExecution = new JDBCUpdateExecution(command, connection, context, config);
try {
updateExecution.execute();
fail();
} catch (TranslatorBatchException e) {
int[] counts = e.getUpdateCounts();
assertArrayEquals(new int[] { 1, -3 }, counts);
}
// test multiple batches
connection = Mockito.mock(Connection.class);
updateExecution = new JDBCUpdateExecution(command, connection, context, config);
command.setParameterValues(Arrays.asList(Arrays.asList(1), Arrays.asList(1)).iterator());
s = Mockito.mock(PreparedStatement.class);
Mockito.stub(connection.prepareStatement("INSERT INTO SmallA (IntKey) VALUES (?)")).toReturn(s);
Mockito.stub(s.executeBatch()).toReturn(new int[] { 1 }).toThrow(new BatchUpdateException(new int[] { Statement.EXECUTE_FAILED }));
updateExecution.setMaxPreparedInsertBatchSize(1);
try {
updateExecution.execute();
fail();
} catch (TranslatorBatchException e) {
int[] counts = e.getUpdateCounts();
assertArrayEquals(new int[] { 1, -3 }, counts);
}
// test only a single update count
connection = Mockito.mock(Connection.class);
updateExecution = new JDBCUpdateExecution(command, connection, context, config);
command.setParameterValues(Arrays.asList(Arrays.asList(1), Arrays.asList(1)).iterator());
s = Mockito.mock(PreparedStatement.class);
Mockito.stub(connection.prepareStatement("INSERT INTO SmallA (IntKey) VALUES (?)")).toReturn(s);
Mockito.stub(s.executeBatch()).toThrow(new BatchUpdateException(new int[] { 1 }));
try {
updateExecution.execute();
fail();
} catch (TranslatorBatchException e) {
int[] counts = e.getUpdateCounts();
assertArrayEquals(new int[] { 1 }, counts);
}
}
use of org.teiid.translator.TranslatorBatchException in project teiid by teiid.
the class TestJDBCUpdateExecution method testBatchedUpdateFailed.
@Test
public void testBatchedUpdateFailed() throws Exception {
// $NON-NLS-1$
Insert command = (Insert) TranslationHelper.helpTranslate(TranslationHelper.BQT_VDB, "insert into BQT1.SmallA (IntKey) values (1)");
// $NON-NLS-1$
Insert command1 = (Insert) TranslationHelper.helpTranslate(TranslationHelper.BQT_VDB, "insert into BQT1.SmallA (StringKey) values ('1')");
Connection connection = Mockito.mock(Connection.class);
Statement s = Mockito.mock(Statement.class);
Mockito.stub(s.executeBatch()).toThrow(new BatchUpdateException(new int[] { Statement.EXECUTE_FAILED }));
Mockito.stub(connection.createStatement()).toReturn(s);
JDBCExecutionFactory config = new JDBCExecutionFactory();
ResultSet r = Mockito.mock(ResultSet.class);
ResultSetMetaData rs = Mockito.mock(ResultSetMetaData.class);
Mockito.stub(r.getMetaData()).toReturn(rs);
Mockito.stub(s.getGeneratedKeys()).toReturn(r);
FakeExecutionContextImpl context = new FakeExecutionContextImpl();
JDBCUpdateExecution updateExecution = new JDBCUpdateExecution(new BatchedUpdates(Arrays.asList((Command) command, command1)), connection, context, config);
try {
updateExecution.execute();
fail();
} catch (TranslatorBatchException e) {
int[] counts = e.getUpdateCounts();
assertArrayEquals(new int[] { -3 }, counts);
}
}
use of org.teiid.translator.TranslatorBatchException in project teiid by teiid.
the class BatchedUpdatePlan method nextBatch.
/**
* @see org.teiid.query.processor.ProcessorPlan#nextBatch()
* @since 4.2
*/
public TupleBatch nextBatch() throws BlockedException, TeiidComponentException, TeiidProcessingException {
for (; planIndex < updatePlans.length && (getContext() == null || getContext().getBatchUpdateException() == null); ) {
try {
if (!planOpened[planIndex]) {
// Open the plan only once
/* Defect 16166
* Some commands in a batch may depend on updates by previous commands in the same batch. A call
* to open() usually submits an atomic command, so calling open() on all the child plans at the same time
* will mean that the datasource may not be in the state expected by a later command within the batch. So,
* for a batch of commands, we only open() a later plan when we are finished with the previous plan to
* guarantee that the commands in the previous plan are completed before the commands in any subsequent
* plans are executed.
*/
openPlan();
} else if (this.planContexts[planIndex] != null) {
this.getContext().getTransactionServer().resume(this.planContexts[planIndex]);
}
// Execute nextBatch() on each plan in sequence
TupleBatch nextBatch = null;
do {
// Can throw BlockedException
nextBatch = updatePlans[planIndex].nextBatch();
List<List<?>> currentBatch = nextBatch.getTuples();
for (int i = 0; i < currentBatch.size(); i++, commandIndex++) {
updateCounts[commandIndex] = currentBatch.get(i);
}
} while (!nextBatch.getTerminationFlag());
// since we are done with the plan explicitly close it.
updatePlans[planIndex].close();
if (this.planContexts[planIndex] != null) {
TransactionService ts = this.getContext().getTransactionServer();
ts.commit(this.planContexts[planIndex]);
this.planContexts[planIndex] = null;
}
planIndex++;
} catch (BlockedException e) {
throw e;
} catch (TeiidComponentException | TeiidProcessingException e) {
if (singleResult) {
throw e;
}
Throwable cause = e;
if (e.getCause() instanceof TranslatorBatchException) {
TranslatorBatchException tbe = (TranslatorBatchException) e.getCause();
for (int i = 0; i < tbe.getUpdateCounts().length; i++) {
updateCounts[commandIndex++] = Arrays.asList(tbe.getUpdateCounts()[i]);
}
}
updateCounts = Arrays.copyOf(updateCounts, commandIndex);
getContext().setBatchUpdateException(cause);
} finally {
if (planIndex < updatePlans.length && this.planContexts[planIndex] != null) {
this.getContext().getTransactionServer().suspend(this.planContexts[planIndex]);
}
}
}
if (singleResult) {
long result = 0;
for (int i = 0; i < updateCounts.length; i++) {
int value = (Integer) updateCounts[i].get(0);
if (value == Statement.EXECUTE_FAILED) {
// the batch results rather than throwing an exception
throw new TeiidProcessingException(QueryPlugin.Event.TEIID31199, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31198));
}
if (value > 0) {
result += value;
}
}
TupleBatch batch = new TupleBatch(1, new List<?>[] { Arrays.asList((int) Math.min(Integer.MAX_VALUE, result)) });
batch.setTerminationFlag(true);
return batch;
}
// Add tuples to current batch
TupleBatch batch = new TupleBatch(1, updateCounts);
batch.setTerminationFlag(true);
return batch;
}
Aggregations