use of herddb.model.StatementExecutionResult in project herddb by diennea.
the class ServerSideConnectionPeer method executeGet.
/**
* This method is like {@link #handleExecuteStatement(herddb.proto.Pdu, herddb.network.Channel) } but in "local" mode,
* we do not want here to marshal/unmarshal values, in order to save resources
*/
public herddb.client.GetResult executeGet(String tablespace, String query, long txId, List<Object> parameters) throws HDBException {
// ensure we are dealing with the same data types that we see when the request id coming from the wire
parameters = PduCodec.normalizeParametersList(parameters);
TransactionContext transactionContext = new TransactionContext(txId);
TranslatedQuery translatedQuery;
try {
translatedQuery = server.getManager().getPlanner().translate(tablespace, query, parameters, false, true, true, -1);
Statement statement = translatedQuery.plan.mainStatement;
CompletableFuture<StatementExecutionResult> res = server.getManager().executePlanAsync(translatedQuery.plan, translatedQuery.context, transactionContext);
CompletableFuture<herddb.client.GetResult> finalResult = res.handle((result, err) -> {
if (err != null) {
while (err instanceof CompletionException) {
err = err.getCause();
}
if (err instanceof DuplicatePrimaryKeyException) {
throw new CompletionException(new SQLIntegrityConstraintViolationException(err));
} else {
throw new CompletionException(new SQLException(err));
}
}
if (result instanceof GetResult) {
GetResult get = (GetResult) result;
if (!get.found()) {
return new herddb.client.GetResult(null, get.transactionId);
} else {
Map<String, Object> record = get.getRecord().toBean(get.getTable());
Map<RawString, Object> recordForClient = new HashMap<>(record.size());
record.forEach((k, v) -> {
recordForClient.put(RawString.of(k), v);
});
return new herddb.client.GetResult(recordForClient, get.transactionId);
}
} else {
throw new CompletionException(new SQLException("Unknown result type " + result.getClass() + ": " + result));
}
});
return finalResult.get();
} catch (Throwable err) {
while (err instanceof CompletionException) {
err = err.getCause();
}
throw new HDBException(err);
}
}
use of herddb.model.StatementExecutionResult in project herddb by diennea.
the class ServerSideConnectionPeer method handleExecuteStatement.
private void handleExecuteStatement(Pdu message, Channel channel) {
long txId = PduCodec.ExecuteStatement.readTx(message);
String tablespace = PduCodec.ExecuteStatement.readTablespace(message);
long statementId = PduCodec.ExecuteStatement.readStatementId(message);
String query = statementId > 0 ? preparedStatements.resolveQuery(tablespace, statementId) : PduCodec.ExecuteStatement.readQuery(message);
if (query == null) {
ByteBuf error = PduCodec.ErrorResponse.writeMissingPreparedStatementError(message.messageId, "bad statement id: " + statementId);
channel.sendReplyMessage(message.messageId, error);
message.close();
return;
}
boolean returnValues = PduCodec.ExecuteStatement.readReturnValues(message);
PduCodec.ObjectListReader parametersReader = PduCodec.ExecuteStatement.startReadParameters(message);
List<Object> parameters = new ArrayList<>(parametersReader.getNumParams());
for (int i = 0; i < parametersReader.getNumParams(); i++) {
parameters.add(parametersReader.nextObject());
}
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "query {0} with {1}", new Object[] { query, parameters });
}
RunningStatementInfo statementInfo = new RunningStatementInfo(query, System.currentTimeMillis(), tablespace, "", 1);
TransactionContext transactionContext = new TransactionContext(txId);
TranslatedQuery translatedQuery;
try {
translatedQuery = server.getManager().getPlanner().translate(tablespace, query, parameters, false, true, returnValues, -1);
} catch (StatementExecutionException ex) {
ByteBuf error = composeErrorResponse(message.messageId, ex);
channel.sendReplyMessage(message.messageId, error);
message.close();
return;
}
Statement statement = translatedQuery.plan.mainStatement;
// LOGGER.log(Level.SEVERE, "query " + query + ", " + parameters + ", plan: " + translatedQuery.plan);
RunningStatementsStats runningStatements = server.getManager().getRunningStatements();
runningStatements.registerRunningStatement(statementInfo);
CompletableFuture<StatementExecutionResult> res = server.getManager().executePlanAsync(translatedQuery.plan, translatedQuery.context, transactionContext);
// LOGGER.log(Level.SEVERE, "query " + query + ", " + parameters + ", result:" + result);
res.whenComplete((result, err) -> {
try {
runningStatements.unregisterRunningStatement(statementInfo);
if (err != null) {
while (err instanceof CompletionException) {
err = err.getCause();
}
if (err instanceof DuplicatePrimaryKeyException) {
ByteBuf error = PduCodec.ErrorResponse.writeSqlIntegrityConstraintsViolation(message.messageId, new SQLIntegrityConstraintViolationException(err));
channel.sendReplyMessage(message.messageId, error);
} else if (err instanceof NotLeaderException) {
ByteBuf error = composeErrorResponse(message.messageId, err);
channel.sendReplyMessage(message.messageId, error);
} else if (err instanceof StatementExecutionException) {
ByteBuf error = composeErrorResponse(message.messageId, err);
channel.sendReplyMessage(message.messageId, error);
} else {
LOGGER.log(Level.SEVERE, "unexpected error on query " + query + ", parameters: " + parameters + ":" + err, err);
ByteBuf error = composeErrorResponse(message.messageId, err);
channel.sendReplyMessage(message.messageId, error);
}
return;
}
if (result instanceof DMLStatementExecutionResult) {
DMLStatementExecutionResult dml = (DMLStatementExecutionResult) result;
Map<String, Object> newRecord = null;
if (returnValues && dml.getKey() != null) {
TableAwareStatement tableStatement = statement.unwrap(TableAwareStatement.class);
Table table = server.getManager().getTableSpaceManager(statement.getTableSpace()).getTableManager(tableStatement.getTable()).getTable();
newRecord = new HashMap<>();
Object newKey = RecordSerializer.deserializePrimaryKey(dml.getKey(), table);
newRecord.put("_key", newKey);
if (dml.getNewvalue() != null) {
newRecord.putAll(RecordSerializer.toBean(new Record(dml.getKey(), dml.getNewvalue()), table));
}
}
channel.sendReplyMessage(message.messageId, PduCodec.ExecuteStatementResult.write(message.messageId, dml.getUpdateCount(), dml.transactionId, newRecord));
} else if (result instanceof GetResult) {
GetResult get = (GetResult) result;
if (!get.found()) {
channel.sendReplyMessage(message.messageId, PduCodec.ExecuteStatementResult.write(message.messageId, 0, get.transactionId, null));
} else {
Map<String, Object> record = get.getRecord().toBean(get.getTable());
channel.sendReplyMessage(message.messageId, PduCodec.ExecuteStatementResult.write(message.messageId, 1, get.transactionId, record));
}
} else if (result instanceof TransactionResult) {
TransactionResult txresult = (TransactionResult) result;
channel.sendReplyMessage(message.messageId, PduCodec.ExecuteStatementResult.write(message.messageId, 1, txresult.getTransactionId(), null));
} else if (result instanceof DDLStatementExecutionResult) {
DDLStatementExecutionResult ddl = (DDLStatementExecutionResult) result;
channel.sendReplyMessage(message.messageId, PduCodec.ExecuteStatementResult.write(message.messageId, 1, ddl.transactionId, null));
} else if (result instanceof DataConsistencyStatementResult) {
channel.sendReplyMessage(message.messageId, PduCodec.ExecuteStatementResult.write(message.messageId, 0, 0, null));
} else {
ByteBuf error = PduCodec.ErrorResponse.write(message.messageId, "unknown result type:" + result);
channel.sendReplyMessage(message.messageId, error);
}
} finally {
message.close();
}
});
}
use of herddb.model.StatementExecutionResult in project herddb by diennea.
the class TableManager method executeDeleteAsync.
private CompletableFuture<StatementExecutionResult> executeDeleteAsync(DeleteStatement delete, Transaction transaction, StatementEvaluationContext context) {
AtomicInteger updateCount = new AtomicInteger();
Holder<Bytes> lastKey = new Holder<>();
Holder<Bytes> lastValue = new Holder<>();
long transactionId = transaction != null ? transaction.transactionId : 0;
Predicate predicate = delete.getPredicate();
List<CompletableFuture<PendingLogEntryWork>> writes = new ArrayList<>();
Map<String, AbstractIndexManager> indexes = tableSpaceManager.getIndexesOnTable(table.name);
ScanStatement scan = new ScanStatement(table.tablespace, table, predicate);
try {
accessTableData(scan, context, new ScanResultOperation() {
@Override
public void accept(Record current, LockHandle lockHandle) throws StatementExecutionException, LogNotAvailableException, DataStorageManagerException {
// ensure we are holding the write locks on every unique index
List<UniqueIndexLockReference> uniqueIndexes = null;
try {
if (indexes != null || childrenTables != null) {
DataAccessor dataAccessor = current.getDataAccessor(table);
if (childrenTables != null) {
for (Table childTable : childrenTables) {
executeForeignKeyConstraintsAsParentTable(childTable, dataAccessor, context, transaction, true);
}
}
if (indexes != null) {
for (AbstractIndexManager index : indexes.values()) {
if (index.isUnique()) {
Bytes indexKey = RecordSerializer.serializeIndexKey(dataAccessor, index.getIndex(), index.getColumnNames());
if (uniqueIndexes == null) {
uniqueIndexes = new ArrayList<>(1);
}
UniqueIndexLockReference uniqueIndexLock = new UniqueIndexLockReference(index, indexKey);
uniqueIndexes.add(uniqueIndexLock);
LockHandle lockForIndex = lockForWrite(uniqueIndexLock.key, transaction, index.getIndexName(), index.getLockManager());
if (transaction == null) {
uniqueIndexLock.lockHandle = lockForIndex;
}
}
}
}
}
} catch (IllegalArgumentException | herddb.utils.IllegalDataAccessException | StatementExecutionException err) {
locksManager.releaseLock(lockHandle);
StatementExecutionException finalError;
if (!(err instanceof StatementExecutionException)) {
finalError = new StatementExecutionException(err.getMessage(), err);
} else {
finalError = (StatementExecutionException) err;
}
CompletableFuture<PendingLogEntryWork> res = Futures.exception(finalError);
if (uniqueIndexes != null) {
for (UniqueIndexLockReference lock : uniqueIndexes) {
res = releaseWriteLock(res, lockHandle, lock.indexManager.getLockManager());
}
}
writes.add(res);
return;
}
LogEntry entry = LogEntryFactory.delete(table, current.key, transaction);
CommitLogResult pos = log.log(entry, entry.transactionId <= 0);
final List<UniqueIndexLockReference> _uniqueIndexes = uniqueIndexes;
writes.add(pos.logSequenceNumber.thenApply(lsn -> new PendingLogEntryWork(entry, pos, lockHandle, _uniqueIndexes)));
lastKey.value = current.key;
lastValue.value = current.value;
updateCount.incrementAndGet();
}
}, transaction, true, true);
} catch (HerdDBInternalException err) {
LOGGER.log(Level.SEVERE, "bad error during a delete", err);
return Futures.exception(err);
}
if (writes.isEmpty()) {
return CompletableFuture.completedFuture(new DMLStatementExecutionResult(transactionId, 0, null, null));
}
if (writes.size() == 1) {
return writes.get(0).whenCompleteAsync((pending, error) -> {
try {
// apply any of the DML operations
if (error == null) {
apply(pending.pos, pending.entry, false);
}
} finally {
releaseMultiplePendingLogEntryWorks(writes);
}
}, tableSpaceManager.getCallbacksExecutor()).thenApply((pending) -> {
return new DMLStatementExecutionResult(transactionId, updateCount.get(), lastKey.value, delete.isReturnValues() ? lastValue.value : null);
});
} else {
return Futures.collect(writes).whenCompleteAsync((pendings, error) -> {
try {
// apply any of the DML operations
if (error == null) {
for (PendingLogEntryWork pending : pendings) {
apply(pending.pos, pending.entry, false);
}
}
} finally {
releaseMultiplePendingLogEntryWorks(writes);
}
}, tableSpaceManager.getCallbacksExecutor()).thenApply((pendings) -> {
return new DMLStatementExecutionResult(transactionId, updateCount.get(), lastKey.value, delete.isReturnValues() ? lastValue.value : null);
});
}
}
use of herddb.model.StatementExecutionResult in project herddb by diennea.
the class TableSpaceManager method executeTableAwareStatement.
private CompletableFuture<StatementExecutionResult> executeTableAwareStatement(Statement statement, Transaction transaction, StatementEvaluationContext context) throws StatementExecutionException {
long lockStamp = context.getTableSpaceLock();
boolean lockAcquired = false;
if (lockStamp == 0) {
lockStamp = acquireReadLock(statement);
context.setTableSpaceLock(lockStamp);
lockAcquired = true;
}
TableAwareStatement st = (TableAwareStatement) statement;
String table = st.getTable();
AbstractTableManager manager = tables.get(table);
CompletableFuture<StatementExecutionResult> res;
if (manager == null) {
res = Futures.exception(new TableDoesNotExistException("no table " + table + " in tablespace " + tableSpaceName));
} else if (manager.getCreatedInTransaction() > 0 && (transaction == null || transaction.transactionId != manager.getCreatedInTransaction())) {
res = Futures.exception(new TableDoesNotExistException("no table " + table + " in tablespace " + tableSpaceName + ". created temporary in transaction " + manager.getCreatedInTransaction()));
} else {
res = manager.executeStatementAsync(statement, transaction, context);
}
if (lockAcquired) {
res = releaseReadLock(res, lockStamp, statement).whenComplete((s, err) -> {
context.setTableSpaceLock(0);
});
}
return res;
}
use of herddb.model.StatementExecutionResult in project herddb by diennea.
the class TableSpaceManager method beginTransactionAsync.
private CompletableFuture<StatementExecutionResult> beginTransactionAsync(StatementEvaluationContext context, boolean releaseLock) throws StatementExecutionException {
long id = newTransactionId.incrementAndGet();
LogEntry entry = LogEntryFactory.beginTransaction(id);
CommitLogResult pos;
boolean lockAcquired = false;
if (context.getTableSpaceLock() == 0) {
long lockStamp = acquireReadLock("begin transaction");
context.setTableSpaceLock(lockStamp);
lockAcquired = true;
}
pos = log.log(entry, false);
CompletableFuture<StatementExecutionResult> res = pos.logSequenceNumber.thenApplyAsync((lsn) -> {
apply(pos, entry, false);
return new TransactionResult(id, TransactionResult.OutcomeType.BEGIN);
}, callbacksExecutor);
if (lockAcquired && releaseLock) {
releaseReadLock(res, context.getTableSpaceLock(), "begin transaction");
}
return res;
}
Aggregations