use of herddb.sql.TranslatedQuery in project herddb by diennea.
the class ServerSideConnectionPeer method executeUpdates.
public List<DMLResult> executeUpdates(String tableSpace, String query, long transactionId, boolean returnValues, List<List<Object>> originalBatch) throws HDBException {
if (query == null) {
throw new HDBException("bad query null");
}
List<List<Object>> batch = new ArrayList<>(originalBatch.size());
for (int i = 0; i < originalBatch.size(); i++) {
batch.add(PduCodec.normalizeParametersList(originalBatch.get(i)));
}
try {
List<TranslatedQuery> queries = new ArrayList<>();
for (int i = 0; i < batch.size(); i++) {
List<Object> parameters = batch.get(i);
TranslatedQuery translatedQuery = server.getManager().getPlanner().translate(tableSpace, query, parameters, false, true, returnValues, -1);
queries.add(translatedQuery);
}
List<Long> updateCounts = new CopyOnWriteArrayList<>();
List<Map<RawString, Object>> otherDatas = new CopyOnWriteArrayList<>();
CompletableFuture<Long> finalResult = new CompletableFuture<>();
class ComputeNext implements BiConsumer<StatementExecutionResult, Throwable> {
int current;
public ComputeNext(int current) {
this.current = current;
}
@Override
public void accept(StatementExecutionResult result, Throwable error) {
if (error != null) {
finalResult.completeExceptionally(error);
return;
}
if (result instanceof DMLStatementExecutionResult) {
DMLStatementExecutionResult dml = (DMLStatementExecutionResult) result;
final Map<RawString, Object> otherData;
if (returnValues && dml.getKey() != null) {
TranslatedQuery translatedQuery = queries.get(current - 1);
Statement statement = translatedQuery.plan.mainStatement;
TableAwareStatement tableStatement = (TableAwareStatement) statement;
Table table = server.getManager().getTableSpaceManager(statement.getTableSpace()).getTableManager(tableStatement.getTable()).getTable();
Object key = RecordSerializer.deserializePrimaryKey(dml.getKey(), table);
otherData = new HashMap<>();
otherData.put(RAWSTRING_KEY, key);
if (dml.getNewvalue() != null) {
Map<String, Object> newvalue = RecordSerializer.toBean(new Record(dml.getKey(), dml.getNewvalue()), table);
newvalue.forEach((k, v) -> {
otherData.put(RawString.of(k), v);
});
}
} else {
otherData = Collections.emptyMap();
}
updateCounts.add((long) dml.getUpdateCount());
otherDatas.add(otherData);
} else if (result instanceof DDLStatementExecutionResult) {
Map<RawString, Object> otherData = Collections.emptyMap();
updateCounts.add(1L);
otherDatas.add(otherData);
} else {
finalResult.completeExceptionally(new Exception("bad result type " + result.getClass() + " (" + result + ")"));
return;
}
long newTransactionId = result.transactionId;
if (current == queries.size()) {
try {
finalResult.complete(newTransactionId);
} catch (Throwable t) {
finalResult.completeExceptionally(t);
}
return;
}
TranslatedQuery nextPlannedQuery = queries.get(current);
TransactionContext transactionContext = new TransactionContext(newTransactionId);
CompletableFuture<StatementExecutionResult> nextPromise = server.getManager().executePlanAsync(nextPlannedQuery.plan, nextPlannedQuery.context, transactionContext);
nextPromise.whenComplete(new ComputeNext(current + 1));
}
}
TransactionContext transactionContext = new TransactionContext(transactionId);
TranslatedQuery firstTranslatedQuery = queries.get(0);
server.getManager().executePlanAsync(firstTranslatedQuery.plan, firstTranslatedQuery.context, transactionContext).whenComplete(new ComputeNext(1));
long finalTransactionId = finalResult.get();
List<DMLResult> returnedValues = new ArrayList<>();
for (int i = 0; i < updateCounts.size(); i++) {
returnedValues.add(new DMLResult(updateCounts.get(i), otherDatas.get(i).get(RAWSTRING_KEY), otherDatas.get(i), finalTransactionId));
}
return returnedValues;
} catch (HerdDBInternalException err) {
throw new HDBException(err);
} catch (InterruptedException err) {
Thread.currentThread().interrupt();
throw new HDBException(err);
} catch (ExecutionException err) {
throw new HDBException(err.getCause());
}
}
use of herddb.sql.TranslatedQuery in project herddb by diennea.
the class ServerSideConnectionPeer method handleOpenScanner.
private void handleOpenScanner(Pdu message, Channel channel) {
long txId = PduCodec.OpenScanner.readTx(message);
String tableSpace = PduCodec.OpenScanner.readTablespace(message);
long statementId = PduCodec.OpenScanner.readStatementId(message);
String query = statementId > 0 ? preparedStatements.resolveQuery(tableSpace, statementId) : PduCodec.OpenScanner.readQuery(message);
if (query == null) {
ByteBuf error = PduCodec.ErrorResponse.writeMissingPreparedStatementError(message.messageId, "bad statement id: " + statementId);
channel.sendReplyMessage(message.messageId, error);
return;
}
long scannerId = PduCodec.OpenScanner.readScannerId(message);
int fetchSize = PduCodec.OpenScanner.readFetchSize(message);
if (fetchSize <= 0) {
fetchSize = 10;
}
// default 0
int maxRows = PduCodec.OpenScanner.readMaxRows(message);
PduCodec.ObjectListReader parametersReader = PduCodec.OpenScanner.startReadParameters(message);
List<Object> parameters = new ArrayList<>(parametersReader.getNumParams());
for (int i = 0; i < parametersReader.getNumParams(); i++) {
parameters.add(parametersReader.nextObject());
}
// with clients older than 0.20.0 keepReadLocks will be always true
byte trailer = parametersReader.readTrailer();
boolean keepReadLocks = !isDontKeepReadLocks(trailer);
if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.log(Level.FINER, "openScanner txId+" + txId + ", fetchSize " + fetchSize + ", maxRows " + maxRows + ", keepReadLocks " + keepReadLocks + ", " + query + " with " + parameters);
}
RunningStatementsStats runningStatements = server.getManager().getRunningStatements();
RunningStatementInfo statementInfo = new RunningStatementInfo(query, System.currentTimeMillis(), tableSpace, "", 1);
try {
TranslatedQuery translatedQuery = server.getManager().getPlanner().translate(tableSpace, query, parameters, true, true, false, maxRows);
translatedQuery.context.setForceRetainReadLock(keepReadLocks);
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "{0} -> {1}", new Object[] { query, translatedQuery.plan.mainStatement });
}
TransactionContext transactionContext = new TransactionContext(txId);
if (translatedQuery.plan.mainStatement instanceof SQLPlannedOperationStatement || translatedQuery.plan.mainStatement instanceof ScanStatement) {
runningStatements.registerRunningStatement(statementInfo);
ScanResult scanResult = (ScanResult) server.getManager().executePlan(translatedQuery.plan, translatedQuery.context, transactionContext);
DataScanner dataScanner = scanResult.dataScanner;
ServerSideScannerPeer scanner = new ServerSideScannerPeer(dataScanner);
String[] columns = dataScanner.getFieldNames();
List<DataAccessor> records = dataScanner.consume(fetchSize);
TuplesList tuplesList = new TuplesList(columns, records);
boolean last = dataScanner.isFinished();
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "sending first {0} records to scanner {1} query {2}", new Object[] { records.size(), scannerId, query });
}
if (!last) {
scanners.put(scannerId, scanner);
}
try {
ByteBuf result = PduCodec.ResultSetChunk.write(message.messageId, tuplesList, last, dataScanner.getTransactionId());
channel.sendReplyMessage(message.messageId, result);
} catch (HerdDBInternalException err) {
// do not leak an unserializable scanner
scanner.close();
throw err;
}
if (last) {
// no need to hold the scanner anymore
scanner.close();
}
} else {
ByteBuf error = PduCodec.ErrorResponse.write(message.messageId, "unsupported query type for scan " + query + ": PLAN is " + translatedQuery.plan);
channel.sendReplyMessage(message.messageId, error);
}
} catch (DataScannerException | HerdDBInternalException err) {
if (err.getCause() != null && err.getCause() instanceof ValidationException) {
// no stacktraces for bad queries
LOGGER.log(Level.FINE, "SQL error on scanner " + scannerId + ": " + err);
} else {
LOGGER.log(Level.SEVERE, "error on scanner " + scannerId + ": " + err, err);
}
scanners.remove(scannerId);
ByteBuf error = composeErrorResponse(message.messageId, err);
channel.sendReplyMessage(message.messageId, error);
} finally {
runningStatements.unregisterRunningStatement(statementInfo);
}
}
use of herddb.sql.TranslatedQuery 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.sql.TranslatedQuery 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();
}
});
}
Aggregations