// countVars counts how many *QualifiedName and *qvalue nodes are in an expression. func countVars(expr parser.Expr) (numQNames, numQValues int) { v := countVarsVisitor{} if expr != nil { parser.WalkExprConst(&v, expr) } return v.numQNames, v.numQValues }
func (p *planner) aggregateInExpr(expr parser.Expr) bool { if expr != nil { defer p.isAggregateVisitor.reset() parser.WalkExprConst(&p.isAggregateVisitor, expr) if p.isAggregateVisitor.aggregated { return true } } return false }
func (p *planner) isAggregate(n *parser.Select) bool { if n.Having != nil || len(n.GroupBy) > 0 { return true } defer p.isAggregateVisitor.reset() for _, target := range n.Exprs { parser.WalkExprConst(&p.isAggregateVisitor, target.Expr) if p.isAggregateVisitor.aggregated { return true } } return false }
// Checks if the given expression only has vars that are known to the conversion function. func exprCheckVars(expr parser.Expr, conv varConvertFunc) bool { v := varConvertVisitor{justCheck: true, conv: conv} parser.WalkExprConst(&v, expr) return !v.checkFailed }
func (v *extractAggregatesVisitor) VisitPre(expr parser.Expr) (recurse bool, newExpr parser.Expr) { if v.err != nil { return false, expr } // This expression is in the GROUP BY - switch to the visitor that will accept // qvalues for this and any subtrees. if _, ok := v.groupStrs[expr.String()]; ok && v.groupedCopy != nil && v != v.groupedCopy { expr, _ = parser.WalkExpr(v.groupedCopy, expr) return false, expr } switch t := expr.(type) { case *parser.FuncExpr: if len(t.Name.Indirect) > 0 { break } if impl, ok := aggregates[strings.ToLower(string(t.Name.Base))]; ok { if len(t.Exprs) != 1 { // Type checking has already run on these expressions thus // if an aggregate function of the wrong arity gets here, // something has gone really wrong. panic(fmt.Sprintf("%s has %d arguments (expected 1)", t.Name.Base, len(t.Exprs))) } defer v.subAggregateVisitor.reset() parser.WalkExprConst(&v.subAggregateVisitor, t.Exprs[0]) if v.subAggregateVisitor.aggregated { v.err = fmt.Errorf("aggregate function calls cannot be nested under %s", t.Name) return false, expr } f := &aggregateFunc{ expr: t, arg: t.Exprs[0], create: impl, group: v.n, buckets: make(map[string]aggregateImpl), } if t.Type == parser.Distinct { f.seen = make(map[string]struct{}) } v.n.funcs = append(v.n.funcs, f) return false, f } case *qvalue: if v.groupedCopy != nil { v.err = fmt.Errorf("column \"%s\" must appear in the GROUP BY clause or be used in an aggregate function", t.colRef.get().Name) return true, expr } f := &aggregateFunc{ expr: t, arg: t, create: newIdentAggregate, group: v.n, buckets: make(map[string]aggregateImpl), } v.n.funcs = append(v.n.funcs, f) return false, f } return true, expr }