use of io.questdb.griffin.model.ExpressionNode in project questdb by bluestreak01.
the class WhereClauseParser method removeWithin.
private boolean removeWithin(AliasTranslator translator, ExpressionNode node, RecordMetadata metadata, FunctionParser functionParser, SqlExecutionContext executionContext, LongList prefixes) throws SqlException {
if (isWithinKeyword(node.token)) {
if (prefixes.size() > 0) {
throw SqlException.$(node.position, "Multiple 'within' expressions not supported");
}
if (node.paramCount < 2) {
throw SqlException.$(node.position, "Too few arguments for 'within'");
}
ExpressionNode col = node.paramCount < 3 ? node.lhs : node.args.getLast();
if (col.type != ExpressionNode.LITERAL) {
throw SqlException.unexpectedToken(col.position, col.token);
}
CharSequence column = translator.translateAlias(col.token);
if (metadata.getColumnIndexQuiet(column) == -1) {
throw SqlException.invalidColumn(col.position, col.token);
}
final int hashColumnIndex = metadata.getColumnIndex(column);
final int hashColumnType = metadata.getColumnType(hashColumnIndex);
if (!ColumnType.isGeoHash(hashColumnType)) {
throw SqlException.$(node.position, "GeoHash column type expected");
}
if (prefixes.size() == 0) {
prefixes.add(hashColumnIndex);
prefixes.add(hashColumnType);
}
int c = node.paramCount - 1;
if (c == 1) {
ExpressionNode inArg = node.rhs;
processArgument(inArg, metadata, functionParser, executionContext, hashColumnType, prefixes);
} else {
for (c--; c > -1; c--) {
ExpressionNode inArg = node.args.getQuick(c);
processArgument(inArg, metadata, functionParser, executionContext, hashColumnType, prefixes);
}
}
return true;
} else {
return false;
}
}
use of io.questdb.griffin.model.ExpressionNode in project questdb by bluestreak01.
the class GroupByUtils method prepareGroupByRecordFunctions.
public static void prepareGroupByRecordFunctions(@NotNull QueryModel model, RecordMetadata metadata, @NotNull ListColumnFilter listColumnFilter, ObjList<GroupByFunction> groupByFunctions, @Transient IntList groupByFunctionPositions, ObjList<Function> recordFunctions, @Transient IntList recordFunctionPositions, GenericRecordMetadata groupByMetadata, ArrayColumnTypes keyTypes, int keyColumnIndex, boolean timestampUnimportant, int timestampIndex) throws SqlException {
recordFunctionPositions.clear();
// Process group-by functions first to get the idea of
// how many map values we will have.
// Map value count is needed to calculate offsets for
// map key columns.
ObjList<QueryColumn> columns = model.getColumns();
int valueColumnIndex = 0;
int inferredKeyColumnCount = 0;
// when we have same column several times in a row
// we only add it once to map keys
int lastIndex = -1;
for (int i = 0, n = columns.size(); i < n; i++) {
final QueryColumn column = columns.getQuick(i);
final ExpressionNode node = column.getAst();
final int type;
if (node.type == ExpressionNode.LITERAL) {
// this is key
int index = metadata.getColumnIndexQuiet(node.token);
if (index == -1) {
throw SqlException.invalidColumn(node.position, node.token);
}
type = metadata.getColumnType(index);
if (index != timestampIndex || timestampUnimportant) {
if (lastIndex != index) {
listColumnFilter.add(index + 1);
keyTypes.add(type);
keyColumnIndex++;
lastIndex = index;
}
final Function fun;
switch(ColumnType.tagOf(type)) {
case ColumnType.BOOLEAN:
fun = BooleanColumn.newInstance(keyColumnIndex - 1);
break;
case ColumnType.BYTE:
fun = ByteColumn.newInstance(keyColumnIndex - 1);
break;
case ColumnType.SHORT:
fun = ShortColumn.newInstance(keyColumnIndex - 1);
break;
case ColumnType.CHAR:
fun = CharColumn.newInstance(keyColumnIndex - 1);
break;
case ColumnType.INT:
fun = IntColumn.newInstance(keyColumnIndex - 1);
break;
case ColumnType.LONG:
fun = LongColumn.newInstance(keyColumnIndex - 1);
break;
case ColumnType.FLOAT:
fun = FloatColumn.newInstance(keyColumnIndex - 1);
break;
case ColumnType.DOUBLE:
fun = DoubleColumn.newInstance(keyColumnIndex - 1);
break;
case ColumnType.STRING:
fun = StrColumn.newInstance(keyColumnIndex - 1);
break;
case ColumnType.SYMBOL:
fun = new MapSymbolColumn(keyColumnIndex - 1, index, metadata.isSymbolTableStatic(index));
break;
case ColumnType.DATE:
fun = DateColumn.newInstance(keyColumnIndex - 1);
break;
case ColumnType.TIMESTAMP:
fun = TimestampColumn.newInstance(keyColumnIndex - 1);
break;
case ColumnType.LONG256:
fun = Long256Column.newInstance(keyColumnIndex - 1);
break;
default:
fun = BinColumn.newInstance(keyColumnIndex - 1);
break;
}
recordFunctions.add(fun);
recordFunctionPositions.add(node.position);
} else {
// set this function to null, cursor will replace it with an instance class
// timestamp function returns value of class member which makes it impossible
// to create these columns in advance of cursor instantiation
recordFunctions.add(null);
groupByFunctionPositions.add(0);
if (groupByMetadata.getTimestampIndex() == -1) {
groupByMetadata.setTimestampIndex(i);
}
assert ColumnType.tagOf(type) == ColumnType.TIMESTAMP;
}
// and finish with populating metadata for this factory
if (column.getAlias() == null) {
groupByMetadata.add(BaseRecordMetadata.copyOf(metadata, index));
} else {
groupByMetadata.add(new TableColumnMetadata(Chars.toString(column.getAlias()), metadata.getColumnHash(index), type, metadata.isColumnIndexed(index), metadata.getIndexValueBlockCapacity(index), metadata.isSymbolTableStatic(index), metadata.getMetadata(index)));
}
inferredKeyColumnCount++;
} else {
// add group-by function as a record function as well
// so it can produce column values
final GroupByFunction groupByFunction = groupByFunctions.getQuick(valueColumnIndex);
recordFunctions.add(groupByFunction);
recordFunctionPositions.add(groupByFunctionPositions.getQuick(valueColumnIndex++));
type = groupByFunction.getType();
// and finish with populating metadata for this factory
groupByMetadata.add(new TableColumnMetadata(Chars.toString(column.getName()), 0, type, false, 0, groupByFunction instanceof SymbolFunction && (((SymbolFunction) groupByFunction).isSymbolTableStatic()), groupByFunction.getMetadata()));
}
}
validateGroupByColumns(model, inferredKeyColumnCount);
}
use of io.questdb.griffin.model.ExpressionNode in project questdb by bluestreak01.
the class GroupByUtils method prepareGroupByFunctions.
public static void prepareGroupByFunctions(QueryModel model, RecordMetadata metadata, FunctionParser functionParser, SqlExecutionContext executionContext, ObjList<GroupByFunction> groupByFunctions, @Transient IntList groupByFunctionPositions, ArrayColumnTypes valueTypes) throws SqlException {
groupByFunctionPositions.clear();
final ObjList<QueryColumn> columns = model.getColumns();
for (int i = 0, n = columns.size(); i < n; i++) {
final QueryColumn column = columns.getQuick(i);
final ExpressionNode node = column.getAst();
if (node.type != ExpressionNode.LITERAL) {
// this can fail
ExpressionNode columnAst = column.getAst();
final Function function = functionParser.parseFunction(columnAst, metadata, executionContext);
// so we have them do all the work
assert function instanceof GroupByFunction;
GroupByFunction func = (GroupByFunction) function;
func.pushValueTypes(valueTypes);
groupByFunctions.add(func);
groupByFunctionPositions.add(columnAst.position);
}
}
}
use of io.questdb.griffin.model.ExpressionNode in project questdb by bluestreak01.
the class GroupByUtils method validateGroupByColumns.
public static void validateGroupByColumns(@NotNull QueryModel model, int inferredKeyColumnCount) throws SqlException {
final ObjList<ExpressionNode> groupByColumns = model.getGroupBy();
int explicitKeyColumnCount = groupByColumns.size();
if (explicitKeyColumnCount == 0) {
return;
}
final QueryModel nested = model.getNestedModel();
QueryModel chooseModel = model;
while (chooseModel != null && chooseModel.getSelectModelType() != QueryModel.SELECT_MODEL_CHOOSE && chooseModel.getSelectModelType() != QueryModel.SELECT_MODEL_NONE) {
chooseModel = chooseModel.getNestedModel();
}
for (int i = 0; i < explicitKeyColumnCount; i++) {
final ExpressionNode key = groupByColumns.getQuick(i);
switch(key.type) {
case ExpressionNode.LITERAL:
final int dotIndex = Chars.indexOf(key.token, '.');
if (dotIndex > -1) {
int aliasIndex = model.getAliasIndex(key.token, 0, dotIndex);
if (aliasIndex > -1) {
// we should now check against main model
int refColumn = model.getAliasToColumnMap().keyIndex(key.token);
if (refColumn > -1) {
// a.x not found, look for "x"
refColumn = model.getAliasToColumnMap().keyIndex(key.token, dotIndex + 1, key.token.length());
}
if (refColumn > -1) {
throw SqlException.$(key.position, "group by column does not match any key column is select statement");
}
} else {
if (chooseModel != null && chooseModel.getColumnNameToAliasMap().keyIndex(key.token) < 0) {
continue;
}
throw SqlException.$(key.position, "invalid column reference");
}
} else {
int refColumn = model.getAliasToColumnMap().keyIndex(key.token);
if (refColumn > -1) {
throw SqlException.$(key.position, "group by column does not match any key column is select statement");
}
QueryColumn qc = model.getAliasToColumnMap().valueAt(refColumn);
if (qc.getAst().type != ExpressionNode.LITERAL && qc.getAst().type != ExpressionNode.CONSTANT) {
throw SqlException.$(key.position, "group by column references aggregate expression");
}
}
break;
case ExpressionNode.BIND_VARIABLE:
throw SqlException.$(key.position, "bind variable is not allowed here");
case ExpressionNode.FUNCTION:
case ExpressionNode.OPERATION:
case ExpressionNode.CONSTANT:
final ObjList<QueryColumn> availableColumns = nested.getTopDownColumns();
boolean invalid = true;
for (int j = 0, n = availableColumns.size(); j < n; j++) {
final QueryColumn qc = availableColumns.getQuick(j);
if (qc.getAst().type == key.type) {
if (ExpressionNode.compareNodesGroupBy(key, qc.getAst(), chooseModel)) {
invalid = false;
break;
}
}
}
if (invalid) {
throw SqlException.$(key.position, "group by expression does not match anything select in statement");
}
break;
default:
throw SqlException.$(key.position, "unsupported type of expression");
}
}
if (explicitKeyColumnCount < inferredKeyColumnCount) {
throw SqlException.$(model.getModelPosition(), "not enough columns in group by");
}
}
use of io.questdb.griffin.model.ExpressionNode in project questdb by bluestreak01.
the class SampleByFirstLastRecordCursorFactory method buildFirstLastIndex.
private void buildFirstLastIndex(int[] firstLastIndex, int[] queryToFrameColumnMapping, RecordMetadata metadata, ObjList<QueryColumn> columns, int timestampIndex) throws SqlException {
for (int i = 0, n = firstLastIndex.length; i < n; i++) {
QueryColumn column = columns.getQuick(i);
ExpressionNode ast = column.getAst();
int resultSetColumnType = groupByMetadata.getColumnType(i);
if (ast.rhs != null) {
if (SqlKeywords.isLastFunction(ast.token)) {
firstLastIndex[i] = LAST_OUT_INDEX;
} else if (SqlKeywords.isFirstFunction(ast.token)) {
firstLastIndex[i] = FIRST_OUT_INDEX;
} else {
throw SqlException.$(ast.position, "expected first() or last() functions but got ").put(ast.token);
}
int underlyingColIndex = metadata.getColumnIndex(ast.rhs.token);
queryToFrameColumnMapping[i] = underlyingColIndex;
int underlyingType = metadata.getColumnType(underlyingColIndex);
if (underlyingType != resultSetColumnType || ColumnType.pow2SizeOf(resultSetColumnType) > 3) {
throw SqlException.$(ast.position, "column \"").put(metadata.getColumnName(underlyingColIndex)).put("\": first(), last() is not supported on data type ").put(ColumnType.nameOf(underlyingType)).put(" ");
}
} else {
int underlyingColIndex = metadata.getColumnIndex(ast.token);
queryToFrameColumnMapping[i] = underlyingColIndex;
if (underlyingColIndex == timestampIndex) {
groupByTimestampIndex = i;
}
}
}
}
Aggregations