public override ulong LogicAggCE(LogicAgg node) { ulong card = 1; if (node.groupby_ is null) { card = 1; } else { ulong distinct = 1; foreach (var v in node.groupby_) { ulong ndistinct = 1; if (v is ColExpr vc && vc.tabRef_ is BaseTableRef bvc) { var stat = Catalog.sysstat_.GetColumnStat(bvc.relname_, vc.colName_); ndistinct = stat.n_distinct_; } // stop accumulating in case of overflow if (distinct * ndistinct > distinct) { distinct *= ndistinct; } } card = (ulong)distinct; } // it won't go beyond the number of output rows return(Math.Min(card, node.child_().Card())); }
public override CGroupMember Apply(CGroupMember expr) { // for manually binding the expression void manualbindexpr(Expr e) { e.bounded_ = true; e.type_ = new BoolType(); } // for transformaing original having according to the new agg func BinExpr processhaving(Expr e, Dictionary <Expr, Expr> dict) { var be = e as BinExpr; Debug.Assert(be != null); bool isreplace = false; List <Expr> children = new List <Expr>(); foreach (var child in be.children_) { if (dict.ContainsKey(child)) { children.Add(dict[child]); isreplace = true; } else { children.Add(child); } } Debug.Assert(isreplace); return(new BinExpr(children[0], children[1], be.op_)); } LogicAgg origAggNode = (expr.logic_ as LogicAgg); var childNode = (origAggNode.child_() as LogicMemoRef).Deref <LogicNode>(); var groupby = origAggNode.groupby_?.CloneList(); var having = origAggNode.having_?.Clone(); // process the aggregation functions origAggNode.GenerateAggrFns(false); List <AggFunc> aggfns = new List <AggFunc>(); origAggNode.aggrFns_.ForEach(x => aggfns.Add(x.Clone() as AggFunc)); // need to make aggrFns_ back to null list origAggNode.aggrFns_ = new List <AggFunc>(); var globalfns = new List <Expr>(); var localfns = new List <Expr>(); // record the processed aggregate functions var derivedAggFuncDict = new Dictionary <Expr, Expr>(); foreach (var func in aggfns) { Expr processed = func.SplitAgg(); // if splitagg is returning null, end the transformation process if (processed is null) { return(expr); } // force the id to be equal. processed._ = func._; globalfns.Add(processed); derivedAggFuncDict.Add(func, processed); } var local = new LogicAgg(childNode, groupby, localfns, null); local.isLocal_ = true; // having is placed on the global agg and the agg func need to be processed var newhaving = having; if (having != null) { newhaving = processhaving(having, derivedAggFuncDict); manualbindexpr(newhaving); } // assuming having is an expression involving agg func, // it is only placed on the global agg var global = new LogicAgg(local, groupby, globalfns, newhaving); global.isDerived_ = true; global.Overridesign(origAggNode); global.deriveddict_ = derivedAggFuncDict; return(new CGroupMember(global, expr.group_)); }