use of org.apache.calcite.sql.validate.AggregatingSelectScope in project calcite by apache.
the class SqlAbstractGroupFunction method validateCall.
@Override
public void validateCall(SqlCall call, SqlValidator validator, SqlValidatorScope scope, SqlValidatorScope operandScope) {
super.validateCall(call, validator, scope, operandScope);
final SelectScope selectScope = SqlValidatorUtil.getEnclosingSelectScope(scope);
assert selectScope != null;
final SqlSelect select = selectScope.getNode();
if (!validator.isAggregate(select)) {
throw validator.newValidationError(call, Static.RESOURCE.groupingInAggregate(getName()));
}
final AggregatingSelectScope aggregatingSelectScope = SqlValidatorUtil.getEnclosingAggregateSelectScope(scope);
if (aggregatingSelectScope == null) {
// We're probably in the GROUP BY clause
throw validator.newValidationError(call, Static.RESOURCE.groupingInWrongClause(getName()));
}
for (SqlNode operand : call.getOperandList()) {
if (scope instanceof OrderByScope) {
operand = validator.expandOrderExpr(select, operand);
} else {
operand = validator.expand(operand, scope);
}
if (!aggregatingSelectScope.resolved.get().isGroupingExpr(operand)) {
throw validator.newValidationError(operand, Static.RESOURCE.groupingArgument(getName()));
}
}
}
use of org.apache.calcite.sql.validate.AggregatingSelectScope in project calcite by apache.
the class SqlToRelConverter method createAggImpl.
protected final void createAggImpl(Blackboard bb, final AggConverter aggConverter, SqlNodeList selectList, SqlNodeList groupList, SqlNode having, List<SqlNode> orderExprList) {
// Find aggregate functions in SELECT and HAVING clause
final AggregateFinder aggregateFinder = new AggregateFinder();
selectList.accept(aggregateFinder);
if (having != null) {
having.accept(aggregateFinder);
}
// first replace the sub-queries inside the aggregates
// because they will provide input rows to the aggregates.
replaceSubQueries(bb, aggregateFinder.list, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
// also replace sub-queries inside filters in the aggregates
replaceSubQueries(bb, aggregateFinder.filterList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
// If group-by clause is missing, pretend that it has zero elements.
if (groupList == null) {
groupList = SqlNodeList.EMPTY;
}
replaceSubQueries(bb, groupList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
// register the group exprs
// build a map to remember the projections from the top scope to the
// output of the current root.
//
// Calcite allows expressions, not just column references in
// group by list. This is not SQL 2003 compliant, but hey.
final AggregatingSelectScope scope = aggConverter.aggregatingSelectScope;
final AggregatingSelectScope.Resolved r = scope.resolved.get();
for (SqlNode groupExpr : r.groupExprList) {
aggConverter.addGroupExpr(groupExpr);
}
final RexNode havingExpr;
final List<Pair<RexNode, String>> projects = Lists.newArrayList();
try {
Preconditions.checkArgument(bb.agg == null, "already in agg mode");
bb.agg = aggConverter;
// convert the select and having expressions, so that the
// agg converter knows which aggregations are required
selectList.accept(aggConverter);
// Assert we don't have dangling items left in the stack
assert !aggConverter.inOver;
for (SqlNode expr : orderExprList) {
expr.accept(aggConverter);
assert !aggConverter.inOver;
}
if (having != null) {
having.accept(aggConverter);
assert !aggConverter.inOver;
}
// compute inputs to the aggregator
List<Pair<RexNode, String>> preExprs = aggConverter.getPreExprs();
if (preExprs.size() == 0) {
// Special case for COUNT(*), where we can end up with no inputs
// at all. The rest of the system doesn't like 0-tuples, so we
// select a dummy constant here.
final RexNode zero = rexBuilder.makeExactLiteral(BigDecimal.ZERO);
preExprs = ImmutableList.of(Pair.of(zero, (String) null));
}
final RelNode inputRel = bb.root;
// Project the expressions required by agg and having.
bb.setRoot(relBuilder.push(inputRel).projectNamed(Pair.left(preExprs), Pair.right(preExprs), false).build(), false);
bb.mapRootRelToFieldProjection.put(bb.root, r.groupExprProjection);
// REVIEW jvs 31-Oct-2007: doesn't the declaration of
// monotonicity here assume sort-based aggregation at
// the physical level?
// Tell bb which of group columns are sorted.
bb.columnMonotonicities.clear();
for (SqlNode groupItem : groupList) {
bb.columnMonotonicities.add(bb.scope.getMonotonicity(groupItem));
}
// Add the aggregator
bb.setRoot(createAggregate(bb, r.groupSet, r.groupSets, aggConverter.getAggCalls()), false);
bb.mapRootRelToFieldProjection.put(bb.root, r.groupExprProjection);
// the replaced expressions
if (having != null) {
SqlNode newHaving = pushDownNotForIn(bb.scope, having);
replaceSubQueries(bb, newHaving, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
havingExpr = bb.convertExpression(newHaving);
} else {
havingExpr = relBuilder.literal(true);
}
// Now convert the other sub-queries in the select list.
// This needs to be done separately from the sub-query inside
// any aggregate in the select list, and after the aggregate rel
// is allocated.
replaceSubQueries(bb, selectList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
// Now sub-queries in the entire select list have been converted.
// Convert the select expressions to get the final list to be
// projected.
int k = 0;
// For select expressions, use the field names previously assigned
// by the validator. If we derive afresh, we might generate names
// like "EXPR$2" that don't match the names generated by the
// validator. This is especially the case when there are system
// fields; system fields appear in the relnode's rowtype but do not
// (yet) appear in the validator type.
final SelectScope selectScope = SqlValidatorUtil.getEnclosingSelectScope(bb.scope);
assert selectScope != null;
final SqlValidatorNamespace selectNamespace = validator.getNamespace(selectScope.getNode());
final List<String> names = selectNamespace.getRowType().getFieldNames();
int sysFieldCount = selectList.size() - names.size();
for (SqlNode expr : selectList) {
projects.add(Pair.of(bb.convertExpression(expr), k < sysFieldCount ? validator.deriveAlias(expr, k++) : names.get(k++ - sysFieldCount)));
}
for (SqlNode expr : orderExprList) {
projects.add(Pair.of(bb.convertExpression(expr), validator.deriveAlias(expr, k++)));
}
} finally {
bb.agg = null;
}
// implement HAVING (we have already checked that it is non-trivial)
relBuilder.push(bb.root);
if (havingExpr != null) {
relBuilder.filter(havingExpr);
}
// implement the SELECT list
relBuilder.project(Pair.left(projects), Pair.right(projects)).rename(Pair.right(projects));
bb.setRoot(relBuilder.build(), false);
// Tell bb which of group columns are sorted.
bb.columnMonotonicities.clear();
for (SqlNode selectItem : selectList) {
bb.columnMonotonicities.add(bb.scope.getMonotonicity(selectItem));
}
}
Aggregations