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;
}
}
Aggregations