Search in sources :

Example 1 with GroupByRecordCursorFactory

use of io.questdb.griffin.engine.groupby.vect.GroupByRecordCursorFactory in project questdb by bluestreak01.

the class SqlCodeGenerator method generateSelectGroupBy.

private RecordCursorFactory generateSelectGroupBy(QueryModel model, SqlExecutionContext executionContext) throws SqlException {
    // fail fast if we cannot create timestamp sampler
    final ExpressionNode sampleByNode = model.getSampleBy();
    if (sampleByNode != null) {
        return generateSampleBy(model, executionContext, sampleByNode, model.getSampleByUnit());
    }
    RecordCursorFactory factory = null;
    try {
        ObjList<QueryColumn> columns;
        ExpressionNode columnExpr;
        // generate special case plan for "select count() from somewhere"
        columns = model.getColumns();
        if (columns.size() == 1) {
            CharSequence columnName = columns.getQuick(0).getName();
            columnExpr = columns.getQuick(0).getAst();
            if (columnExpr.type == FUNCTION && columnExpr.paramCount == 0 && isCountKeyword(columnExpr.token)) {
                // check if count() was not aliased, if it was, we need to generate new metadata, bummer
                final RecordMetadata metadata = isCountKeyword(columnName) ? CountRecordCursorFactory.DEFAULT_COUNT_METADATA : new GenericRecordMetadata().add(new TableColumnMetadata(Chars.toString(columnName), 0, ColumnType.LONG));
                return new CountRecordCursorFactory(metadata, generateSubQuery(model, executionContext));
            }
        }
        tempKeyIndexesInBase.clear();
        tempKeyIndex.clear();
        arrayColumnTypes.clear();
        tempKeyKinds.clear();
        boolean pageFramingSupported = false;
        boolean specialCaseKeys = false;
        // check for special case time function aggregations
        final QueryModel nested = model.getNestedModel();
        assert nested != null;
        // check if underlying model has reference to hour(column) function
        if (nested.getSelectModelType() == QueryModel.SELECT_MODEL_VIRTUAL && (columnExpr = nested.getColumns().getQuick(0).getAst()).type == FUNCTION && isHourKeyword(columnExpr.token) && columnExpr.paramCount == 1 && columnExpr.rhs.type == LITERAL) {
            specialCaseKeys = true;
            factory = generateSubQuery(nested, executionContext);
            pageFramingSupported = factory.supportPageFrameCursor();
            if (pageFramingSupported) {
                // find position of the hour() argument in the factory meta
                tempKeyIndexesInBase.add(factory.getMetadata().getColumnIndex(columnExpr.rhs.token));
                // find position of hour() alias in selected columns
                // also make sure there are no other literal column than our function reference
                final CharSequence functionColumnName = columns.getQuick(0).getName();
                for (int i = 0, n = columns.size(); i < n; i++) {
                    columnExpr = columns.getQuick(i).getAst();
                    if (columnExpr.type == LITERAL) {
                        if (Chars.equals(columnExpr.token, functionColumnName)) {
                            tempKeyIndex.add(i);
                            // storage dimension for Rosti is INT when we use hour(). This function produces INT.
                            tempKeyKinds.add(GKK_HOUR_INT);
                            arrayColumnTypes.add(ColumnType.INT);
                        } else {
                            // there is something else here, fallback to default implementation
                            pageFramingSupported = false;
                            break;
                        }
                    }
                }
            } else {
                factory = Misc.free(factory);
            }
        }
        if (factory == null) {
            factory = generateSubQuery(model, executionContext);
            pageFramingSupported = factory.supportPageFrameCursor();
        }
        RecordMetadata metadata = factory.getMetadata();
        // inspect model for possibility of vector aggregate intrinsics
        if (pageFramingSupported && assembleKeysAndFunctionReferences(columns, metadata, !specialCaseKeys)) {
            // create metadata from everything we've gathered
            GenericRecordMetadata meta = new GenericRecordMetadata();
            // start with keys
            for (int i = 0, n = tempKeyIndex.size(); i < n; i++) {
                final int indexInThis = tempKeyIndex.getQuick(i);
                final int indexInBase = tempKeyIndexesInBase.getQuick(i);
                final int type = arrayColumnTypes.getColumnType(i);
                if (ColumnType.isSymbol(type)) {
                    meta.add(indexInThis, new TableColumnMetadata(Chars.toString(columns.getQuick(indexInThis).getName()), 0, type, false, 0, metadata.isSymbolTableStatic(indexInBase), null));
                } else {
                    meta.add(indexInThis, new TableColumnMetadata(Chars.toString(columns.getQuick(indexInThis).getName()), 0, type, null));
                }
            }
            // add aggregates
            for (int i = 0, n = tempVecConstructors.size(); i < n; i++) {
                VectorAggregateFunctionConstructor constructor = tempVecConstructors.getQuick(i);
                int indexInBase = tempVecConstructorArgIndexes.getQuick(i);
                int indexInThis = tempAggIndex.getQuick(i);
                VectorAggregateFunction vaf = constructor.create(tempKeyKinds.size() == 0 ? 0 : tempKeyKinds.getQuick(0), indexInBase, executionContext.getWorkerCount());
                tempVaf.add(vaf);
                meta.add(indexInThis, new TableColumnMetadata(Chars.toString(columns.getQuick(indexInThis).getName()), 0, vaf.getType(), null));
            }
            if (tempKeyIndexesInBase.size() == 0) {
                return new GroupByNotKeyedVectorRecordCursorFactory(configuration, factory, meta, tempVaf);
            }
            if (tempKeyIndexesInBase.size() == 1) {
                for (int i = 0, n = tempVaf.size(); i < n; i++) {
                    tempVaf.getQuick(i).pushValueTypes(arrayColumnTypes);
                }
                GroupByUtils.validateGroupByColumns(model, 1);
                return new GroupByRecordCursorFactory(configuration, factory, meta, arrayColumnTypes, executionContext.getWorkerCount(), tempVaf, tempKeyIndexesInBase.getQuick(0), tempKeyIndex.getQuick(0), tempSymbolSkewIndexes);
            }
        }
        if (specialCaseKeys) {
            // uh-oh, we had special case keys, but could not find implementation for the functions
            // release factory we created unnecessarily
            Misc.free(factory);
            // create factory on top level model
            factory = generateSubQuery(model, executionContext);
            // and reset metadata
            metadata = factory.getMetadata();
        }
        final int timestampIndex = getTimestampIndex(model, factory);
        keyTypes.clear();
        valueTypes.clear();
        listColumnFilterA.clear();
        final int columnCount = model.getColumns().size();
        ObjList<GroupByFunction> groupByFunctions = new ObjList<>(columnCount);
        GroupByUtils.prepareGroupByFunctions(model, metadata, functionParser, executionContext, groupByFunctions, groupByFunctionPositions, valueTypes);
        final ObjList<Function> recordFunctions = new ObjList<>(columnCount);
        final GenericRecordMetadata groupByMetadata = new GenericRecordMetadata();
        GroupByUtils.prepareGroupByRecordFunctions(model, metadata, listColumnFilterA, groupByFunctions, groupByFunctionPositions, recordFunctions, recordFunctionPositions, groupByMetadata, keyTypes, valueTypes.getColumnCount(), true, timestampIndex);
        if (keyTypes.getColumnCount() == 0) {
            return new GroupByNotKeyedRecordCursorFactory(factory, groupByMetadata, groupByFunctions, recordFunctions, valueTypes.getColumnCount());
        }
        return new io.questdb.griffin.engine.groupby.GroupByRecordCursorFactory(configuration, factory, listColumnFilterA, asm, keyTypes, valueTypes, groupByMetadata, groupByFunctions, recordFunctions);
    } catch (Throwable e) {
        Misc.free(factory);
        throw e;
    }
}
Also used : GroupByFunction(io.questdb.griffin.engine.functions.GroupByFunction) SymbolFunction(io.questdb.griffin.engine.functions.SymbolFunction) GroupByFunction(io.questdb.griffin.engine.functions.GroupByFunction) AnalyticFunction(io.questdb.griffin.engine.analytic.AnalyticFunction) GroupByRecordCursorFactory(io.questdb.griffin.engine.groupby.vect.GroupByRecordCursorFactory) QueryModel(io.questdb.griffin.model.QueryModel) SortedLightRecordCursorFactory(io.questdb.griffin.engine.orderby.SortedLightRecordCursorFactory) SortedRecordCursorFactory(io.questdb.griffin.engine.orderby.SortedRecordCursorFactory) LimitRecordCursorFactory(io.questdb.griffin.engine.LimitRecordCursorFactory) GroupByRecordCursorFactory(io.questdb.griffin.engine.groupby.vect.GroupByRecordCursorFactory) EmptyTableRecordCursorFactory(io.questdb.griffin.engine.EmptyTableRecordCursorFactory) CachedAnalyticRecordCursorFactory(io.questdb.griffin.engine.analytic.CachedAnalyticRecordCursorFactory)

Aggregations

EmptyTableRecordCursorFactory (io.questdb.griffin.engine.EmptyTableRecordCursorFactory)1 LimitRecordCursorFactory (io.questdb.griffin.engine.LimitRecordCursorFactory)1 AnalyticFunction (io.questdb.griffin.engine.analytic.AnalyticFunction)1 CachedAnalyticRecordCursorFactory (io.questdb.griffin.engine.analytic.CachedAnalyticRecordCursorFactory)1 GroupByFunction (io.questdb.griffin.engine.functions.GroupByFunction)1 SymbolFunction (io.questdb.griffin.engine.functions.SymbolFunction)1 GroupByRecordCursorFactory (io.questdb.griffin.engine.groupby.vect.GroupByRecordCursorFactory)1 SortedLightRecordCursorFactory (io.questdb.griffin.engine.orderby.SortedLightRecordCursorFactory)1 SortedRecordCursorFactory (io.questdb.griffin.engine.orderby.SortedRecordCursorFactory)1 QueryModel (io.questdb.griffin.model.QueryModel)1