use of io.crate.expression.symbol.Symbol in project crate by crate.
the class RelationAnalyzer method analyzeGroupBy.
private List<Symbol> analyzeGroupBy(SelectAnalysis selectAnalysis, List<Expression> groupBy, ExpressionAnalyzer expressionAnalyzer, ExpressionAnalysisContext expressionAnalysisContext) {
List<Symbol> groupBySymbols = new ArrayList<>(groupBy.size());
for (Expression expression : groupBy) {
Symbol symbol = symbolFromExpressionFallbackOnSelectOutput(expression, selectAnalysis, "GROUP BY", expressionAnalyzer, expressionAnalysisContext);
GroupBySymbolValidator.validate(symbol);
groupBySymbols.add(symbol);
}
return groupBySymbols;
}
use of io.crate.expression.symbol.Symbol in project crate by crate.
the class RelationAnalyzer method visitQuery.
@Override
protected AnalyzedRelation visitQuery(Query node, StatementAnalysisContext statementContext) {
AnalyzedRelation childRelation = node.getQueryBody().accept(this, statementContext);
if (node.getOrderBy().isEmpty() && node.getLimit().isEmpty() && node.getOffset().isEmpty()) {
return childRelation;
}
// In case of Set Operation (UNION, INTERSECT EXCEPT) or VALUES clause,
// the `node` contains the ORDER BY and/or LIMIT and/or OFFSET and wraps the
// actual operation (eg: UNION) which is parsed into the `queryBody` of the `node`.
// Use child relation to process expressions of the "root" Query node
statementContext.startRelation();
RelationAnalysisContext relationAnalysisContext = statementContext.currentRelationContext();
relationAnalysisContext.addSourceRelation(childRelation);
statementContext.endRelation();
List<Symbol> childRelationFields = childRelation.outputs();
var coordinatorTxnCtx = statementContext.transactionContext();
ExpressionAnalyzer expressionAnalyzer = new ExpressionAnalyzer(coordinatorTxnCtx, nodeCtx, statementContext.paramTyeHints(), new FullQualifiedNameFieldProvider(relationAnalysisContext.sources(), relationAnalysisContext.parentSources(), coordinatorTxnCtx.sessionContext().searchPath().currentSchema()), new SubqueryAnalyzer(this, statementContext));
ExpressionAnalysisContext expressionAnalysisContext = relationAnalysisContext.expressionAnalysisContext();
SelectAnalysis selectAnalysis = new SelectAnalysis(childRelationFields.size(), relationAnalysisContext.sources(), expressionAnalyzer, expressionAnalysisContext);
for (Symbol field : childRelationFields) {
selectAnalysis.add(Symbols.pathFromSymbol(field), field);
}
var normalizer = EvaluatingNormalizer.functionOnlyNormalizer(nodeCtx, f -> expressionAnalysisContext.isEagerNormalizationAllowed() && f.isDeterministic());
return new QueriedSelectRelation(false, List.of(childRelation), List.of(), selectAnalysis.outputSymbols(), Literal.BOOLEAN_TRUE, List.of(), null, analyzeOrderBy(selectAnalysis, node.getOrderBy(), expressionAnalyzer, expressionAnalysisContext, false, false), longSymbolOrNull(node.getLimit(), expressionAnalyzer, expressionAnalysisContext, normalizer, coordinatorTxnCtx), longSymbolOrNull(node.getOffset(), expressionAnalyzer, expressionAnalysisContext, normalizer, coordinatorTxnCtx));
}
use of io.crate.expression.symbol.Symbol in project crate by crate.
the class RelationAnalyzer method analyzeHaving.
@Nullable
private Symbol analyzeHaving(Optional<Expression> having, @Nullable List<Symbol> groupBy, ExpressionAnalyzer expressionAnalyzer, ExpressionAnalysisContext expressionAnalysisContext) {
if (having.isPresent()) {
if (!expressionAnalysisContext.hasAggregates() && (groupBy == null || groupBy.isEmpty())) {
throw new IllegalArgumentException("HAVING clause can only be used in GROUP BY or global aggregate queries");
}
Symbol symbol = expressionAnalyzer.convert(having.get(), expressionAnalysisContext);
HavingSymbolValidator.validate(symbol, groupBy);
return symbol;
}
return null;
}
use of io.crate.expression.symbol.Symbol in project crate by crate.
the class FullQualifiedNameFieldProvider method resolveField.
@Override
public Symbol resolveField(QualifiedName qualifiedName, @Nullable List<String> path, Operation operation, boolean errorOnUnknownObjectKey) {
List<String> parts = qualifiedName.getParts();
String columnSchema = null;
String columnTableName = null;
ColumnIdent columnIdent = new ColumnIdent(parts.get(parts.size() - 1), path);
switch(parts.size()) {
case 1:
break;
case 2:
columnTableName = parts.get(0);
break;
case 3:
columnSchema = parts.get(0);
columnTableName = parts.get(1);
break;
default:
throw new IllegalArgumentException("Column reference \"%s\" has too many parts. " + "A column reference can have at most 3 parts and must have one of the following formats: " + "\"<column>\", \"<table>.<column>\" or \"<schema>.<table>.<column>\"");
}
boolean schemaMatched = false;
boolean tableNameMatched = false;
Symbol lastField = null;
for (var entry : sources.entrySet()) {
RelationName relName = entry.getKey();
String sourceSchema = relName.schema();
String sourceTableOrAlias = relName.name();
if (columnSchema != null && !columnSchema.equals(sourceSchema)) {
continue;
}
schemaMatched = true;
if (columnTableName != null && !sourceTableOrAlias.equals(columnTableName)) {
continue;
}
tableNameMatched = true;
AnalyzedRelation sourceRelation = entry.getValue();
Symbol newField = sourceRelation.getField(columnIdent, operation, errorOnUnknownObjectKey);
if (newField != null) {
if (lastField != null) {
if (errorOnUnknownObjectKey == false) {
/* ex) CREATE TABLE c1 (obj object as (x int));
* CREATE TABLE c2 (obj object as (y int));
* select obj['x'] from c1, c2;
* --> ambiguous because c2.obj['x'] is another candidate with errorOnUnknownObjectKey = false
*/
return resolveField(qualifiedName, path, operation, true);
}
throw new AmbiguousColumnException(columnIdent, newField);
}
lastField = newField;
}
}
if (lastField == null) {
if (!schemaMatched || !tableNameMatched) {
String schema = columnSchema == null ? defaultSchema : columnSchema;
raiseUnsupportedFeatureIfInParentScope(columnSchema, columnTableName, schema);
RelationName relationName = new RelationName(schema, columnTableName);
throw new RelationUnknown(relationName);
}
RelationName relationName = sources.entrySet().iterator().next().getKey();
throw new ColumnUnknownException(columnIdent.sqlFqn(), relationName);
}
return lastField;
}
use of io.crate.expression.symbol.Symbol in project crate by crate.
the class WhereClauseAnalyzer method resolvePartitions.
public static PartitionResult resolvePartitions(Symbol query, DocTableInfo tableInfo, CoordinatorTxnCtx coordinatorTxnCtx, NodeContext nodeCtx) {
assert tableInfo.isPartitioned() : "table must be partitioned in order to resolve partitions";
assert !tableInfo.partitions().isEmpty() : "table must have at least one partition";
PartitionReferenceResolver partitionReferenceResolver = preparePartitionResolver(tableInfo.partitionedByColumns());
EvaluatingNormalizer normalizer = new EvaluatingNormalizer(nodeCtx, RowGranularity.PARTITION, partitionReferenceResolver, null);
Symbol normalized;
Map<Symbol, List<Literal>> queryPartitionMap = new HashMap<>();
for (PartitionName partitionName : tableInfo.partitions()) {
for (PartitionExpression partitionExpression : partitionReferenceResolver.expressions()) {
partitionExpression.setNextRow(partitionName);
}
normalized = normalizer.normalize(query, coordinatorTxnCtx);
assert normalized != null : "normalizing a query must not return null";
if (normalized.equals(query)) {
// no partition columns inside the where clause
return new PartitionResult(query, Collections.emptyList());
}
boolean canMatch = WhereClause.canMatch(normalized);
if (canMatch) {
List<Literal> partitions = queryPartitionMap.get(normalized);
if (partitions == null) {
partitions = new ArrayList<>();
queryPartitionMap.put(normalized, partitions);
}
partitions.add(Literal.of(partitionName.asIndexName()));
}
}
if (queryPartitionMap.size() == 1) {
Map.Entry<Symbol, List<Literal>> entry = Iterables.getOnlyElement(queryPartitionMap.entrySet());
return new PartitionResult(entry.getKey(), Lists2.map(entry.getValue(), literal -> nullOrString(literal.value())));
} else if (queryPartitionMap.size() > 0) {
PartitionResult partitionResult = tieBreakPartitionQueries(normalizer, queryPartitionMap, coordinatorTxnCtx);
return partitionResult == null ? // the query will then be evaluated correctly within each partition to see whether it matches or not
new PartitionResult(query, Lists2.map(tableInfo.partitions(), PartitionName::asIndexName)) : partitionResult;
} else {
return new PartitionResult(Literal.BOOLEAN_FALSE, Collections.emptyList());
}
}
Aggregations