protected override BoundRelation RewriteGroupByAndAggregationRelation(BoundGroupByAndAggregationRelation node) { var aggregates = RemoveUnusedSlots(node.Aggregates, a => a.Output); node = node.Update(node.Input, node.Groups, aggregates); _recorder.Record(node.Aggregates); _recorder.Record(node.Groups); return(base.RewriteGroupByAndAggregationRelation(node)); }
protected override BoundRelation RewriteGroupByAndAggregationRelation(BoundGroupByAndAggregationRelation node) { var input = RewriteRelation(node.Input); if (node.Aggregates.IsEmpty) { return(new BoundSortRelation(true, input, node.Groups)); } var sortedInput = node.Groups.Any() ? new BoundSortRelation(false, input, node.Groups) : input; return(new BoundStreamAggregatesRelation(sortedInput, node.Groups, node.Aggregates)); }
protected override BoundExpression RewriteSingleRowSubselect(BoundSingleRowSubselect node) { var relation = RewriteRelation(node.Relation); var factory = node.Value.Factory; // TODO: If the query is guranteed to return a single, e.g. if it is a aggregated but not grouped, // we should not emit the additional aggregation and assertion. // 1. We need to know whether it returns more then one row. var valueSlot = node.Value; var anyOutput = factory.CreateTemporary(valueSlot.Type); var countOutput = factory.CreateTemporary(typeof(int)); var anyAggregateSymbol = BuiltInAggregates.Any; var anyAggregatable = anyAggregateSymbol.Definition.CreateAggregatable(valueSlot.Type); var countAggregatedSymbol = BuiltInAggregates.Count; var countAggregatable = countAggregatedSymbol.Definition.CreateAggregatable(typeof(int)); var aggregates = new[] { new BoundAggregatedValue(anyOutput, anyAggregateSymbol, anyAggregatable, Expression.Value(valueSlot)), new BoundAggregatedValue(countOutput, countAggregatedSymbol, countAggregatable, Expression.Literal(0)) }; var aggregation = new BoundGroupByAndAggregationRelation(relation, Enumerable.Empty <BoundComparedValue>(), aggregates); // 2. Now we can assert that the number of rows returned is at most one. var condition = Expression.LessThan(Expression.Value(countOutput), Expression.Literal(1)); var message = Resources.SubqueryReturnedMoreThanRow; var assertRelation = new BoundAssertRelation(aggregation, condition, message); var subquery = new Subquery(SubqueryKind.Subselect, anyOutput, assertRelation, CurrentPassthru); var subqueries = _subqueryStack.Peek(); subqueries.Add(subquery); return(Expression.Value(anyOutput)); }
private static CardinalityEstimate EstimateGroupByAndAggregationRelation(BoundGroupByAndAggregationRelation relation) { return(CardinalityEstimate.Unknown); }
private BoundRelation PushOverGroupByAndAggregation(BoundFilterRelation node, BoundGroupByAndAggregationRelation input) { // TODO: This may not be that easy. // // For example this condition can be pushed: // // GroupCol = Value // // while this can't: // // GroupCol = Value OR Func(const) = const // // Formally, a predicate can be pushed over an aggregate if and only if all disjuncts of the predicate's // CNF do reference at least one grouping column. BoundExpression remainder = null; BoundExpression pushed = null; foreach (var conjunction in Expression.SplitConjunctions(node.Condition)) { if (conjunction.DependsOnAny(input.GetDefinedValues())) { remainder = Expression.And(remainder, conjunction); } else { pushed = Expression.And(pushed, conjunction); } } var newInputInput = pushed == null ? input.Input : new BoundFilterRelation(input.Input, pushed); var newInput = RewriteRelation(input.Update(newInputInput, input.Groups, input.Aggregates)); var newNode = remainder == null ? newInput : new BoundFilterRelation(newInput, remainder); return(newNode); }