Пример #1
0
// 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
}
Пример #2
0
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
}
Пример #3
0
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
}
Пример #4
0
// 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
}
Пример #5
0
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
}