use of herddb.sql.expressions.CompiledSQLExpression in project herddb by diennea.
the class CalcitePlanner method planEnumerableJoin.
private PlannerOp planEnumerableJoin(EnumerableHashJoin op, RelDataType rowType) {
// please note that EnumerableJoin has a condition field which actually is not useful
PlannerOp left = convertRelNode(op.getLeft(), null, false, false);
PlannerOp right = convertRelNode(op.getRight(), null, false, false);
final JoinInfo analyzeCondition = op.analyzeCondition();
int[] leftKeys = analyzeCondition.leftKeys.toIntArray();
int[] rightKeys = analyzeCondition.rightKeys.toIntArray();
boolean generateNullsOnLeft = op.getJoinType().generatesNullsOnLeft();
boolean generateNullsOnRight = op.getJoinType().generatesNullsOnRight();
List<CompiledSQLExpression> nonEquiConditions = convertJoinNonEquiConditions(analyzeCondition);
final RelDataType _rowType = rowType == null ? op.getRowType() : rowType;
List<RelDataTypeField> fieldList = _rowType.getFieldList();
Column[] columns = new Column[fieldList.size()];
String[] fieldNames = new String[columns.length];
int i = 0;
for (RelDataTypeField field : fieldList) {
Column col = Column.column(field.getName().toLowerCase(), convertToHerdType(field.getType()));
fieldNames[i] = col.name;
columns[i++] = col;
}
return new JoinOp(fieldNames, columns, leftKeys, left, rightKeys, right, generateNullsOnLeft, generateNullsOnRight, false, nonEquiConditions);
}
use of herddb.sql.expressions.CompiledSQLExpression in project herddb by diennea.
the class CalcitePlanner method planFilter.
private PlannerOp planFilter(EnumerableFilter op, RelDataType rowType, boolean returnValues) {
PlannerOp input = convertRelNode(op.getInput(), rowType, returnValues, false);
CompiledSQLExpression condition = SQLExpressionCompiler.compileExpression(op.getCondition());
return new FilterOp(input, condition);
}
use of herddb.sql.expressions.CompiledSQLExpression in project herddb by diennea.
the class InsertOp method executeAsync.
@Override
public CompletableFuture<StatementExecutionResult> executeAsync(TableSpaceManager tableSpaceManager, TransactionContext transactionContext, StatementEvaluationContext context, boolean lockRequired, boolean forWrite) {
StatementExecutionResult input = this.input.execute(tableSpaceManager, transactionContext, context, true, true);
ScanResult downstreamScanResult = (ScanResult) input;
final Table table = tableSpaceManager.getTableManager(tableName).getTable();
long transactionId = transactionContext.transactionId;
List<DMLStatement> statements = new ArrayList<>();
try (DataScanner inputScanner = downstreamScanResult.dataScanner) {
while (inputScanner.hasNext()) {
DataAccessor row = inputScanner.next();
long transactionIdFromScanner = inputScanner.getTransactionId();
if (transactionIdFromScanner > 0 && transactionIdFromScanner != transactionId) {
transactionId = transactionIdFromScanner;
transactionContext = new TransactionContext(transactionId);
}
int index = 0;
List<CompiledSQLExpression> keyValueExpression = new ArrayList<>();
List<String> keyExpressionToColumn = new ArrayList<>();
List<CompiledSQLExpression> valuesExpressions = new ArrayList<>();
List<String> valuesColumns = new ArrayList<>();
for (Column column : table.getColumns()) {
Object value = row.get(index++);
if (value != null) {
ConstantExpression exp = new ConstantExpression(value, column.type);
if (table.isPrimaryKeyColumn(column.name)) {
keyExpressionToColumn.add(column.name);
keyValueExpression.add(exp);
}
valuesColumns.add(column.name);
valuesExpressions.add(exp);
}
}
RecordFunction keyfunction;
if (keyValueExpression.isEmpty() && table.auto_increment) {
keyfunction = new AutoIncrementPrimaryKeyRecordFunction();
} else {
if (keyValueExpression.size() != table.primaryKey.length) {
throw new StatementExecutionException("you must set a value for the primary key (expressions=" + keyValueExpression.size() + ")");
}
keyfunction = new SQLRecordKeyFunction(keyExpressionToColumn, keyValueExpression, table);
}
RecordFunction valuesfunction = new SQLRecordFunction(valuesColumns, table, valuesExpressions);
DMLStatement insertStatement = new InsertStatement(tableSpace, tableName, keyfunction, valuesfunction, upsert).setReturnValues(returnValues);
statements.add(insertStatement);
}
if (statements.isEmpty()) {
return CompletableFuture.completedFuture(new DMLStatementExecutionResult(transactionId, 0, null, null));
}
if (statements.size() == 1) {
return tableSpaceManager.executeStatementAsync(statements.get(0), context, transactionContext);
}
if (returnValues) {
return Futures.exception(new StatementExecutionException("cannot 'return values' on multi-values insert"));
}
CompletableFuture<StatementExecutionResult> finalResult = new CompletableFuture<>();
AtomicInteger updateCounts = new AtomicInteger();
AtomicReference<Bytes> lastKey = new AtomicReference<>();
AtomicReference<Bytes> lastNewValue = new AtomicReference<>();
class ComputeNext implements BiConsumer<StatementExecutionResult, Throwable> {
int current;
public ComputeNext(int current) {
this.current = current;
}
@Override
public void accept(StatementExecutionResult res, Throwable error) {
if (error != null) {
finalResult.completeExceptionally(error);
return;
}
DMLStatementExecutionResult dml = (DMLStatementExecutionResult) res;
updateCounts.addAndGet(dml.getUpdateCount());
if (returnValues) {
lastKey.set(dml.getKey());
lastNewValue.set(dml.getNewvalue());
}
long newTransactionId = res.transactionId;
if (current == statements.size()) {
DMLStatementExecutionResult finalDMLResult = new DMLStatementExecutionResult(newTransactionId, updateCounts.get(), lastKey.get(), lastNewValue.get());
finalResult.complete(finalDMLResult);
return;
}
DMLStatement nextStatement = statements.get(current);
TransactionContext transactionContext = new TransactionContext(newTransactionId);
CompletableFuture<StatementExecutionResult> nextPromise = tableSpaceManager.executeStatementAsync(nextStatement, context, transactionContext);
nextPromise.whenComplete(new ComputeNext(current + 1));
}
}
DMLStatement firstStatement = statements.get(0);
tableSpaceManager.executeStatementAsync(firstStatement, context, transactionContext).whenComplete(new ComputeNext(1));
return finalResult;
} catch (DataScannerException err) {
throw new StatementExecutionException(err);
}
}
use of herddb.sql.expressions.CompiledSQLExpression in project herddb by diennea.
the class JoinOp method execute.
@Override
public StatementExecutionResult execute(TableSpaceManager tableSpaceManager, TransactionContext transactionContext, StatementEvaluationContext context, boolean lockRequired, boolean forWrite) throws StatementExecutionException {
ScanResult resLeft = (ScanResult) left.execute(tableSpaceManager, transactionContext, context, lockRequired, forWrite);
transactionContext = new TransactionContext(resLeft.transactionId);
ScanResult resRight = (ScanResult) right.execute(tableSpaceManager, transactionContext, context, lockRequired, forWrite);
final long resTransactionId = resRight.transactionId;
DataScanner leftScanner = resLeft.dataScanner;
final String[] fieldNamesFromLeft = leftScanner.getFieldNames();
final String[] fieldNamesFromRight = resRight.dataScanner.getFieldNames();
Function2<DataAccessor, DataAccessor, DataAccessor> resultProjection = resultProjection(fieldNamesFromLeft, fieldNamesFromRight);
final Predicate2 predicate;
DataScanner rightScanner = resRight.dataScanner;
if (nonEquiConditions != null && !nonEquiConditions.isEmpty()) {
if (mergeJoin) {
throw new IllegalStateException("Unspected nonEquiConditions " + nonEquiConditions + "" + "for merge join");
}
predicate = (Predicate2) (Object t0, Object t1) -> {
DataAccessor da0 = (DataAccessor) t0;
DataAccessor da1 = (DataAccessor) t1;
DataAccessor currentRow = resultProjection.apply(da0, da1);
for (CompiledSQLExpression exp : nonEquiConditions) {
Object result = exp.evaluate(currentRow, context);
boolean asBoolean = SQLRecordPredicateFunctions.toBoolean(result);
if (!asBoolean) {
return false;
}
}
return true;
};
} else {
predicate = null;
}
if (!mergeJoin && !leftScanner.isRewindSupported()) {
try {
MaterializedRecordSet recordSet = tableSpaceManager.getDbmanager().getRecordSetFactory().createRecordSet(leftScanner.getFieldNames(), leftScanner.getSchema());
leftScanner.forEach(d -> {
recordSet.add(d);
});
recordSet.writeFinished();
SimpleDataScanner materialized = new SimpleDataScanner(leftScanner.getTransaction(), recordSet);
leftScanner.close();
leftScanner = materialized;
} catch (DataScannerException err) {
throw new StatementExecutionException(err);
}
}
if (!mergeJoin && !rightScanner.isRewindSupported()) {
try {
MaterializedRecordSet recordSet = tableSpaceManager.getDbmanager().getRecordSetFactory().createRecordSet(rightScanner.getFieldNames(), rightScanner.getSchema());
rightScanner.forEach(d -> {
recordSet.add(d);
});
recordSet.writeFinished();
SimpleDataScanner materialized = new SimpleDataScanner(rightScanner.getTransaction(), recordSet);
rightScanner.close();
rightScanner = materialized;
} catch (DataScannerException err) {
throw new StatementExecutionException(err);
}
}
Enumerable<DataAccessor> result = mergeJoin ? EnumerableDefaults.mergeJoin(leftScanner.createNonRewindableEnumerable(), rightScanner.createNonRewindableEnumerable(), JoinKey.keyExtractor(leftKeys), JoinKey.keyExtractor(rightKeys), resultProjection, generateNullsOnLeft, generateNullsOnRight) : EnumerableDefaults.hashJoin(leftScanner.createRewindOnCloseEnumerable(), rightScanner.createRewindOnCloseEnumerable(), JoinKey.keyExtractor(leftKeys), JoinKey.keyExtractor(rightKeys), resultProjection, null, generateNullsOnLeft, generateNullsOnRight, predicate);
EnumerableDataScanner joinedScanner = new EnumerableDataScanner(rightScanner.getTransaction(), fieldNames, columns, result, leftScanner, rightScanner);
return new ScanResult(resTransactionId, joinedScanner);
}
use of herddb.sql.expressions.CompiledSQLExpression in project herddb by diennea.
the class CalcitePlanner method translate.
@Override
public TranslatedQuery translate(String defaultTableSpace, String query, List<Object> parameters, boolean scan, boolean allowCache, boolean returnValues, int maxRows) throws StatementExecutionException {
ensureDefaultTableSpaceBootedLocally(defaultTableSpace);
/* Strips out leading comments */
int idx = SQLUtils.findQueryStart(query);
if (idx != -1) {
query = query.substring(idx);
}
if (parameters == null) {
parameters = Collections.emptyList();
}
String cacheKey = "scan:" + scan + ",defaultTableSpace:" + defaultTableSpace + ",query:" + query + ",returnValues:" + returnValues + ",maxRows:" + maxRows;
boolean forceAcquireWriteLock;
if (// this looks very hacky
query.endsWith(" FOR UPDATE") && query.substring(0, 6).toLowerCase().equals("select")) {
forceAcquireWriteLock = true;
query = query.substring(0, query.length() - " FOR UPDATE".length());
} else {
forceAcquireWriteLock = false;
}
if (allowCache) {
ExecutionPlan cached = cache.get(cacheKey);
if (cached != null) {
return new TranslatedQuery(cached, new SQLStatementEvaluationContext(query, parameters, forceAcquireWriteLock, false));
}
}
if (isDDL(query)) {
query = JSQLParserPlanner.rewriteExecuteSyntax(query);
return fallback.translate(defaultTableSpace, query, parameters, scan, allowCache, returnValues, maxRows);
}
if (query.startsWith(TABLE_CONSISTENCY_COMMAND)) {
query = JSQLParserPlanner.rewriteExecuteSyntax(query);
return fallback.translate(defaultTableSpace, query, parameters, scan, allowCache, returnValues, maxRows);
}
if (query.startsWith(TABLESPACE_CONSISTENCY_COMMAND)) {
query = JSQLParserPlanner.rewriteExecuteSyntax(query);
return fallback.translate(defaultTableSpace, query, parameters, scan, allowCache, returnValues, maxRows);
}
if (!isCachable(query)) {
allowCache = false;
}
try {
if (query.startsWith("EXPLAIN ")) {
query = query.substring("EXPLAIN ".length());
PlannerResult plan = runPlanner(defaultTableSpace, query);
boolean upsert = detectUpsert(plan);
PlannerOp finalPlan = convertRelNode(plan.topNode, plan.originalRowType, returnValues, upsert).optimize();
ValuesOp values = new ValuesOp(manager.getNodeId(), new String[] { "name", "value" }, new Column[] { column("name", ColumnTypes.STRING), column("value", ColumnTypes.STRING) }, java.util.Arrays.asList(java.util.Arrays.asList(new ConstantExpression("query", ColumnTypes.NOTNULL_STRING), new ConstantExpression(query, ColumnTypes.NOTNULL_STRING)), java.util.Arrays.asList(new ConstantExpression("logicalplan", ColumnTypes.NOTNULL_STRING), new ConstantExpression(RelOptUtil.dumpPlan("", plan.logicalPlan, SqlExplainFormat.TEXT, SqlExplainLevel.ALL_ATTRIBUTES), ColumnTypes.NOTNULL_STRING)), java.util.Arrays.asList(new ConstantExpression("plan", ColumnTypes.NOTNULL_STRING), new ConstantExpression(RelOptUtil.dumpPlan("", plan.topNode, SqlExplainFormat.TEXT, SqlExplainLevel.ALL_ATTRIBUTES), ColumnTypes.NOTNULL_STRING)), java.util.Arrays.asList(new ConstantExpression("finalplan", ColumnTypes.NOTNULL_STRING), new ConstantExpression(finalPlan + "", ColumnTypes.NOTNULL_STRING))));
ExecutionPlan executionPlan = ExecutionPlan.simple(new SQLPlannedOperationStatement(values), values);
return new TranslatedQuery(executionPlan, new SQLStatementEvaluationContext(query, parameters, false, false));
}
if (query.startsWith("SHOW")) {
return calculateShowCreateTable(query, defaultTableSpace, parameters, manager);
}
PlannerResult plan = runPlanner(defaultTableSpace, query);
boolean upsert = detectUpsert(plan);
SQLPlannedOperationStatement sqlPlannedOperationStatement = new SQLPlannedOperationStatement(convertRelNode(plan.topNode, plan.originalRowType, returnValues, upsert).optimize());
if (LOG.isLoggable(DUMP_QUERY_LEVEL)) {
LOG.log(DUMP_QUERY_LEVEL, "Query: {0} --HerdDB Plan\n{1}", new Object[] { query, sqlPlannedOperationStatement.getRootOp() });
}
if (!scan) {
ScanStatement scanStatement = sqlPlannedOperationStatement.unwrap(ScanStatement.class);
if (scanStatement != null) {
Table tableDef = scanStatement.getTableDef();
CompiledSQLExpression where = scanStatement.getPredicate().unwrap(CompiledSQLExpression.class);
SQLRecordKeyFunction keyFunction = IndexUtils.findIndexAccess(where, tableDef.getPrimaryKey(), tableDef, "=", tableDef);
if (keyFunction == null || !keyFunction.isFullPrimaryKey()) {
throw new StatementExecutionException("unsupported GET not on PK, bad where clause: " + query);
}
GetStatement get = new GetStatement(scanStatement.getTableSpace(), scanStatement.getTable(), keyFunction, scanStatement.getPredicate(), true);
ExecutionPlan executionPlan = ExecutionPlan.simple(get);
if (allowCache) {
cache.put(cacheKey, executionPlan);
}
return new TranslatedQuery(executionPlan, new SQLStatementEvaluationContext(query, parameters, forceAcquireWriteLock, false));
}
}
if (maxRows > 0) {
PlannerOp op = new LimitOp(sqlPlannedOperationStatement.getRootOp(), new ConstantExpression(maxRows, ColumnTypes.NOTNULL_LONG), new ConstantExpression(0, ColumnTypes.NOTNULL_LONG)).optimize();
sqlPlannedOperationStatement = new SQLPlannedOperationStatement(op);
}
PlannerOp rootOp = sqlPlannedOperationStatement.getRootOp();
ExecutionPlan executionPlan;
if (rootOp.isSimpleStatementWrapper()) {
executionPlan = ExecutionPlan.simple(rootOp.unwrap(herddb.model.Statement.class), rootOp);
} else {
executionPlan = ExecutionPlan.simple(sqlPlannedOperationStatement, rootOp);
}
if (allowCache) {
cache.put(cacheKey, executionPlan);
}
return new TranslatedQuery(executionPlan, new SQLStatementEvaluationContext(query, parameters, forceAcquireWriteLock, false));
} catch (CalciteContextException ex) {
LOG.log(Level.INFO, "Error while parsing '" + ex.getOriginalStatement() + "'", ex);
// TODO can this be done better ?
throw new StatementExecutionException(ex.getMessage());
} catch (RelConversionException | ValidationException | SqlParseException ex) {
LOG.log(Level.INFO, "Error while parsing '" + query + "'", ex);
// TODO can this be done better ?
throw new StatementExecutionException(ex.getMessage().replace("org.apache.calcite.runtime.CalciteContextException: ", ""), ex);
} catch (MetadataStorageManagerException ex) {
LOG.log(Level.INFO, "Error while parsing '" + query + "'", ex);
throw new StatementExecutionException(ex);
}
}
Aggregations