Search in sources :

Example 6 with GroupByFunction

use of io.questdb.griffin.engine.functions.GroupByFunction in project questdb by bluestreak01.

the class SampleByInterpolateRecordCursorFactory method interpolateBoundaryRange.

private void interpolateBoundaryRange(long x1, long x2, Record record) {
    // interpolating boundary
    for (int i = 0; i < groupByTwoPointFunctionCount; i++) {
        GroupByFunction function = groupByTwoPointFunctions.getQuick(i);
        MapValue startValue = findDataMapValue2(record, x1);
        MapValue endValue = findDataMapValue3(record, x2);
        InterpolationUtil.interpolateBoundary(function, sampler.nextTimestamp(x1), startValue, endValue, true);
        InterpolationUtil.interpolateBoundary(function, x2, startValue, endValue, false);
    }
}
Also used : GroupByFunction(io.questdb.griffin.engine.functions.GroupByFunction) MapValue(io.questdb.cairo.map.MapValue)

Example 7 with GroupByFunction

use of io.questdb.griffin.engine.functions.GroupByFunction 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)

Example 8 with GroupByFunction

use of io.questdb.griffin.engine.functions.GroupByFunction in project questdb by bluestreak01.

the class SqlCodeGenerator method generateSampleBy.

@NotNull
private RecordCursorFactory generateSampleBy(QueryModel model, SqlExecutionContext executionContext, ExpressionNode sampleByNode, ExpressionNode sampleByUnits) throws SqlException {
    executionContext.pushTimestampRequiredFlag(true);
    try {
        final ExpressionNode timezoneName = model.getSampleByTimezoneName();
        final Function timezoneNameFunc;
        final int timezoneNameFuncPos;
        final ExpressionNode offset = model.getSampleByOffset();
        final Function offsetFunc;
        final int offsetFuncPos;
        if (timezoneName != null) {
            timezoneNameFunc = functionParser.parseFunction(timezoneName, EmptyRecordMetadata.INSTANCE, executionContext);
            timezoneNameFuncPos = timezoneName.position;
        } else {
            timezoneNameFunc = StrConstant.NULL;
            timezoneNameFuncPos = 0;
        }
        if (offset != null) {
            offsetFunc = functionParser.parseFunction(offset, EmptyRecordMetadata.INSTANCE, executionContext);
            offsetFuncPos = offset.position;
        } else {
            offsetFunc = StrConstant.NULL;
            offsetFuncPos = 0;
        }
        final RecordCursorFactory factory = generateSubQuery(model, executionContext);
        // we require timestamp
        final int timestampIndex = getTimestampIndex(model, factory);
        if (timestampIndex == -1) {
            Misc.free(factory);
            throw SqlException.$(model.getModelPosition(), "base query does not provide dedicated TIMESTAMP column");
        }
        final RecordMetadata metadata = factory.getMetadata();
        final ObjList<ExpressionNode> sampleByFill = model.getSampleByFill();
        final TimestampSampler timestampSampler;
        if (sampleByUnits == null) {
            timestampSampler = TimestampSamplerFactory.getInstance(sampleByNode.token, sampleByNode.position);
        } else {
            Function sampleByPeriod = functionParser.parseFunction(sampleByNode, EmptyRecordMetadata.INSTANCE, executionContext);
            if (!sampleByPeriod.isConstant() || (sampleByPeriod.getType() != ColumnType.LONG && sampleByPeriod.getType() != ColumnType.INT)) {
                sampleByPeriod.close();
                throw SqlException.$(sampleByNode.position, "sample by period must be a constant expression of INT or LONG type");
            }
            long period = sampleByPeriod.getLong(null);
            sampleByPeriod.close();
            timestampSampler = TimestampSamplerFactory.getInstance(period, sampleByUnits.token, sampleByUnits.position);
        }
        final int fillCount = sampleByFill.size();
        try {
            keyTypes.clear();
            valueTypes.clear();
            listColumnFilterA.clear();
            if (fillCount == 1 && Chars.equalsLowerCaseAscii(sampleByFill.getQuick(0).token, "linear")) {
                return new SampleByInterpolateRecordCursorFactory(configuration, factory, timestampSampler, model, listColumnFilterA, functionParser, executionContext, asm, keyTypes, valueTypes, entityColumnFilter, recordFunctionPositions, groupByFunctionPositions, timestampIndex);
            }
            final int columnCount = model.getColumns().size();
            final ObjList<GroupByFunction> groupByFunctions = new ObjList<>(columnCount);
            // first value is always timestamp
            valueTypes.add(ColumnType.TIMESTAMP);
            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(), false, timestampIndex);
            boolean isFillNone = fillCount == 0 || fillCount == 1 && Chars.equalsLowerCaseAscii(sampleByFill.getQuick(0).token, "none");
            boolean allGroupsFirstLast = isFillNone && allGroupsFirstLastWithSingleSymbolFilter(model, metadata);
            if (allGroupsFirstLast) {
                SingleSymbolFilter symbolFilter = factory.convertToSampleByIndexDataFrameCursorFactory();
                if (symbolFilter != null) {
                    return new SampleByFirstLastRecordCursorFactory(factory, timestampSampler, groupByMetadata, model.getColumns(), metadata, timezoneNameFunc, timezoneNameFuncPos, offsetFunc, offsetFuncPos, timestampIndex, symbolFilter, configuration.getSampleByIndexSearchPageSize());
                }
            }
            if (fillCount == 1 && Chars.equalsLowerCaseAscii(sampleByFill.getQuick(0).token, "prev")) {
                if (keyTypes.getColumnCount() == 0) {
                    return new SampleByFillPrevNotKeyedRecordCursorFactory(factory, timestampSampler, groupByMetadata, groupByFunctions, recordFunctions, timestampIndex, valueTypes.getColumnCount(), timezoneNameFunc, timezoneNameFuncPos, offsetFunc, offsetFuncPos);
                }
                return new SampleByFillPrevRecordCursorFactory(configuration, factory, timestampSampler, listColumnFilterA, asm, keyTypes, valueTypes, groupByMetadata, groupByFunctions, recordFunctions, timestampIndex, timezoneNameFunc, timezoneNameFuncPos, offsetFunc, offsetFuncPos);
            }
            if (isFillNone) {
                if (keyTypes.getColumnCount() == 0) {
                    // this sample by is not keyed
                    return new SampleByFillNoneNotKeyedRecordCursorFactory(factory, timestampSampler, groupByMetadata, groupByFunctions, recordFunctions, valueTypes.getColumnCount(), timestampIndex, timezoneNameFunc, timezoneNameFuncPos, offsetFunc, offsetFuncPos);
                }
                return new SampleByFillNoneRecordCursorFactory(configuration, factory, groupByMetadata, groupByFunctions, recordFunctions, timestampSampler, listColumnFilterA, asm, keyTypes, valueTypes, timestampIndex, timezoneNameFunc, timezoneNameFuncPos, offsetFunc, offsetFuncPos);
            }
            if (fillCount == 1 && isNullKeyword(sampleByFill.getQuick(0).token)) {
                if (keyTypes.getColumnCount() == 0) {
                    return new SampleByFillNullNotKeyedRecordCursorFactory(factory, timestampSampler, groupByMetadata, groupByFunctions, recordFunctions, recordFunctionPositions, valueTypes.getColumnCount(), timestampIndex, timezoneNameFunc, timezoneNameFuncPos, offsetFunc, offsetFuncPos);
                }
                return new SampleByFillNullRecordCursorFactory(configuration, factory, timestampSampler, listColumnFilterA, asm, keyTypes, valueTypes, groupByMetadata, groupByFunctions, recordFunctions, recordFunctionPositions, timestampIndex, timezoneNameFunc, timezoneNameFuncPos, offsetFunc, offsetFuncPos);
            }
            assert fillCount > 0;
            if (keyTypes.getColumnCount() == 0) {
                return new SampleByFillValueNotKeyedRecordCursorFactory(factory, timestampSampler, sampleByFill, groupByMetadata, groupByFunctions, recordFunctions, recordFunctionPositions, valueTypes.getColumnCount(), timestampIndex, timezoneNameFunc, timezoneNameFuncPos, offsetFunc, offsetFuncPos);
            }
            return new SampleByFillValueRecordCursorFactory(configuration, factory, timestampSampler, listColumnFilterA, asm, sampleByFill, keyTypes, valueTypes, groupByMetadata, groupByFunctions, recordFunctions, recordFunctionPositions, timestampIndex, timezoneNameFunc, timezoneNameFuncPos, offsetFunc, offsetFuncPos);
        } catch (Throwable e) {
            factory.close();
            throw e;
        }
    } finally {
        executionContext.popTimestampRequiredFlag();
    }
}
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) 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) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

GroupByFunction (io.questdb.griffin.engine.functions.GroupByFunction)8 SymbolFunction (io.questdb.griffin.engine.functions.SymbolFunction)4 Function (io.questdb.cairo.sql.Function)3 ExpressionNode (io.questdb.griffin.model.ExpressionNode)3 MapValue (io.questdb.cairo.map.MapValue)2 EmptyTableRecordCursorFactory (io.questdb.griffin.engine.EmptyTableRecordCursorFactory)2 LimitRecordCursorFactory (io.questdb.griffin.engine.LimitRecordCursorFactory)2 AnalyticFunction (io.questdb.griffin.engine.analytic.AnalyticFunction)2 CachedAnalyticRecordCursorFactory (io.questdb.griffin.engine.analytic.CachedAnalyticRecordCursorFactory)2 GroupByRecordCursorFactory (io.questdb.griffin.engine.groupby.vect.GroupByRecordCursorFactory)2 SortedLightRecordCursorFactory (io.questdb.griffin.engine.orderby.SortedLightRecordCursorFactory)2 SortedRecordCursorFactory (io.questdb.griffin.engine.orderby.SortedRecordCursorFactory)2 QueryColumn (io.questdb.griffin.model.QueryColumn)2 NotNull (org.jetbrains.annotations.NotNull)2 QueryModel (io.questdb.griffin.model.QueryModel)1