Search in sources :

Example 21 with CompiledSQLExpression

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);
}
Also used : PlannerOp(herddb.model.planner.PlannerOp) CompiledSQLExpression(herddb.sql.expressions.CompiledSQLExpression) RelDataType(org.apache.calcite.rel.type.RelDataType) JoinInfo(org.apache.calcite.rel.core.JoinInfo) RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) Column(herddb.model.Column) JoinOp(herddb.model.planner.JoinOp) SemiJoinOp(herddb.model.planner.SemiJoinOp) NestedLoopJoinOp(herddb.model.planner.NestedLoopJoinOp)

Example 22 with CompiledSQLExpression

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);
}
Also used : PlannerOp(herddb.model.planner.PlannerOp) FilterOp(herddb.model.planner.FilterOp) CompiledSQLExpression(herddb.sql.expressions.CompiledSQLExpression)

Example 23 with CompiledSQLExpression

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);
    }
}
Also used : DataAccessor(herddb.utils.DataAccessor) ConstantExpression(herddb.sql.expressions.ConstantExpression) ArrayList(java.util.ArrayList) CompiledSQLExpression(herddb.sql.expressions.CompiledSQLExpression) StatementExecutionException(herddb.model.StatementExecutionException) InsertStatement(herddb.model.commands.InsertStatement) Bytes(herddb.utils.Bytes) CompletableFuture(java.util.concurrent.CompletableFuture) DataScanner(herddb.model.DataScanner) Column(herddb.model.Column) DMLStatementExecutionResult(herddb.model.DMLStatementExecutionResult) StatementExecutionResult(herddb.model.StatementExecutionResult) SQLRecordFunction(herddb.sql.SQLRecordFunction) SQLRecordFunction(herddb.sql.SQLRecordFunction) RecordFunction(herddb.model.RecordFunction) AutoIncrementPrimaryKeyRecordFunction(herddb.model.AutoIncrementPrimaryKeyRecordFunction) SQLRecordKeyFunction(herddb.sql.SQLRecordKeyFunction) DataScannerException(herddb.model.DataScannerException) ScanResult(herddb.model.ScanResult) Table(herddb.model.Table) AtomicReference(java.util.concurrent.atomic.AtomicReference) DMLStatementExecutionResult(herddb.model.DMLStatementExecutionResult) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TransactionContext(herddb.model.TransactionContext) DMLStatement(herddb.model.DMLStatement) AutoIncrementPrimaryKeyRecordFunction(herddb.model.AutoIncrementPrimaryKeyRecordFunction) BiConsumer(java.util.function.BiConsumer)

Example 24 with CompiledSQLExpression

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);
}
Also used : ScanResult(herddb.model.ScanResult) MaterializedRecordSet(herddb.core.MaterializedRecordSet) DataAccessor(herddb.utils.DataAccessor) CompiledSQLExpression(herddb.sql.expressions.CompiledSQLExpression) StatementExecutionException(herddb.model.StatementExecutionException) SimpleDataScanner(herddb.core.SimpleDataScanner) DataScanner(herddb.model.DataScanner) TransactionContext(herddb.model.TransactionContext) Predicate2(org.apache.calcite.linq4j.function.Predicate2) SimpleDataScanner(herddb.core.SimpleDataScanner) DataScannerException(herddb.model.DataScannerException)

Example 25 with CompiledSQLExpression

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);
    }
}
Also used : ValidationException(org.apache.calcite.tools.ValidationException) ConstantExpression(herddb.sql.expressions.ConstantExpression) CompiledSQLExpression(herddb.sql.expressions.CompiledSQLExpression) ValuesOp(herddb.model.planner.ValuesOp) StatementExecutionException(herddb.model.StatementExecutionException) SQLPlannedOperationStatement(herddb.model.commands.SQLPlannedOperationStatement) MetadataStorageManagerException(herddb.metadata.MetadataStorageManagerException) CalciteContextException(org.apache.calcite.runtime.CalciteContextException) ExecutionPlan(herddb.model.ExecutionPlan) ScanStatement(herddb.model.commands.ScanStatement) PlannerOp(herddb.model.planner.PlannerOp) Table(herddb.model.Table) ShowCreateTableCalculator.calculateShowCreateTable(herddb.sql.functions.ShowCreateTableCalculator.calculateShowCreateTable) SqlStdOperatorTable(org.apache.calcite.sql.fun.SqlStdOperatorTable) RelOptTable(org.apache.calcite.plan.RelOptTable) ProjectableFilterableTable(org.apache.calcite.schema.ProjectableFilterableTable) ScannableTable(org.apache.calcite.schema.ScannableTable) AbstractTable(org.apache.calcite.schema.impl.AbstractTable) ModifiableTable(org.apache.calcite.schema.ModifiableTable) SqlParseException(org.apache.calcite.sql.parser.SqlParseException) LimitOp(herddb.model.planner.LimitOp) RelConversionException(org.apache.calcite.tools.RelConversionException) GetStatement(herddb.model.commands.GetStatement)

Aggregations

CompiledSQLExpression (herddb.sql.expressions.CompiledSQLExpression)34 Column (herddb.model.Column)17 ArrayList (java.util.ArrayList)16 Table (herddb.model.Table)15 PlannerOp (herddb.model.planner.PlannerOp)15 StatementExecutionException (herddb.model.StatementExecutionException)13 RecordFunction (herddb.model.RecordFunction)9 ShowCreateTableCalculator.calculateShowCreateTable (herddb.sql.functions.ShowCreateTableCalculator.calculateShowCreateTable)9 AutoIncrementPrimaryKeyRecordFunction (herddb.model.AutoIncrementPrimaryKeyRecordFunction)8 ConstantExpression (herddb.sql.expressions.ConstantExpression)8 TableSpaceManager (herddb.core.TableSpaceManager)7 AccessCurrentRowExpression (herddb.sql.expressions.AccessCurrentRowExpression)7 CompiledMultiAndExpression (herddb.sql.expressions.CompiledMultiAndExpression)7 CreateTable (net.sf.jsqlparser.statement.create.table.CreateTable)7 AbstractTableManager (herddb.core.AbstractTableManager)6 ScanStatement (herddb.model.commands.ScanStatement)6 Expression (net.sf.jsqlparser.expression.Expression)6 SignedExpression (net.sf.jsqlparser.expression.SignedExpression)6 AlterExpression (net.sf.jsqlparser.statement.alter.AlterExpression)6 RelDataType (org.apache.calcite.rel.type.RelDataType)6