promql: make scalar public

This commit is contained in:
Fabian Reinartz 2016-12-24 10:44:04 +01:00
parent b3f71df350
commit 09666e2e2a
6 changed files with 59 additions and 58 deletions

View file

@ -156,7 +156,7 @@ type StringLiteral struct {
} }
// UnaryExpr represents a unary operation on another expression. // UnaryExpr represents a unary operation on another expression.
// Currently unary operations are only supported for scalars. // Currently unary operations are only supported for Scalars.
type UnaryExpr struct { type UnaryExpr struct {
Op itemType Op itemType
Expr Expr Expr Expr

View file

@ -52,7 +52,7 @@ type Value interface {
func (Matrix) Type() ValueType { return ValueTypeMatrix } func (Matrix) Type() ValueType { return ValueTypeMatrix }
func (Vector) Type() ValueType { return ValueTypeVector } func (Vector) Type() ValueType { return ValueTypeVector }
func (scalar) Type() ValueType { return ValueTypeScalar } func (Scalar) Type() ValueType { return ValueTypeScalar }
func (stringVal) Type() ValueType { return ValueTypeString } func (stringVal) Type() ValueType { return ValueTypeString }
// ValueType describes a type of a value. // ValueType describes a type of a value.
@ -62,7 +62,7 @@ type ValueType string
const ( const (
ValueTypeNone = "none" ValueTypeNone = "none"
ValueTypeVector = "Vector" ValueTypeVector = "Vector"
ValueTypeScalar = "scalar" ValueTypeScalar = "Scalar"
ValueTypeMatrix = "Matrix" ValueTypeMatrix = "Matrix"
ValueTypeString = "string" ValueTypeString = "string"
) )
@ -76,12 +76,12 @@ func (s stringVal) String() string {
return s.s return s.s
} }
type scalar struct { type Scalar struct {
t int64 t int64
v float64 v float64
} }
func (s scalar) String() string { func (s Scalar) String() string {
return "" return ""
} }
@ -175,15 +175,15 @@ func (r *Result) Matrix() (Matrix, error) {
return v, nil return v, nil
} }
// Scalar returns a scalar value. An error is returned if // Scalar returns a Scalar value. An error is returned if
// the result was an error or the result value is not a scalar. // the result was an error or the result value is not a Scalar.
func (r *Result) Scalar() (scalar, error) { func (r *Result) Scalar() (Scalar, error) {
if r.Err != nil { if r.Err != nil {
return scalar{}, r.Err return Scalar{}, r.Err
} }
v, ok := r.Value.(scalar) v, ok := r.Value.(Scalar)
if !ok { if !ok {
return scalar{}, fmt.Errorf("query result is not a scalar") return Scalar{}, fmt.Errorf("query result is not a Scalar")
} }
return v, nil return v, nil
} }
@ -336,7 +336,7 @@ func (ng *Engine) NewRangeQuery(qs string, start, end time.Time, interval time.D
return nil, err return nil, err
} }
if expr.Type() != ValueTypeVector && expr.Type() != ValueTypeScalar { if expr.Type() != ValueTypeVector && expr.Type() != ValueTypeScalar {
return nil, fmt.Errorf("invalid expression type %q for range query, must be scalar or instant Vector", documentedType(expr.Type())) return nil, fmt.Errorf("invalid expression type %q for range query, must be Scalar or instant Vector", documentedType(expr.Type()))
} }
qry := ng.newQuery(expr, start, end, interval) qry := ng.newQuery(expr, start, end, interval)
qry.q = qs qry.q = qs
@ -470,9 +470,9 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (
} }
switch v := val.(type) { switch v := val.(type) {
case scalar: case Scalar:
// As the expression type does not change we can safely default to 0 // As the expression type does not change we can safely default to 0
// as the fingerprint for scalar expressions. // as the fingerprint for Scalar expressions.
ss, ok := sampleStreams[0] ss, ok := sampleStreams[0]
if !ok { if !ok {
ss = sampleStream{Values: make([]samplePair, 0, numSteps)} ss = sampleStream{Values: make([]samplePair, 0, numSteps)}
@ -633,12 +633,12 @@ func (ev *evaluator) recover(errp *error) {
} }
} }
// evalScalar attempts to evaluate e to a scalar value and errors otherwise. // evalScalar attempts to evaluate e to a Scalar value and errors otherwise.
func (ev *evaluator) evalScalar(e Expr) scalar { func (ev *evaluator) evalScalar(e Expr) Scalar {
val := ev.eval(e) val := ev.eval(e)
sv, ok := val.(scalar) sv, ok := val.(Scalar)
if !ok { if !ok {
ev.errorf("expected scalar but got %s", documentedType(val.Type())) ev.errorf("expected Scalar but got %s", documentedType(val.Type()))
} }
return sv return sv
} }
@ -657,7 +657,7 @@ func (ev *evaluator) evalVector(e Expr) Vector {
func (ev *evaluator) evalInt(e Expr) int64 { func (ev *evaluator) evalInt(e Expr) int64 {
sc := ev.evalScalar(e) sc := ev.evalScalar(e)
if !convertibleToInt64(sc.v) { if !convertibleToInt64(sc.v) {
ev.errorf("scalar value %v overflows int64", sc.v) ev.errorf("Scalar value %v overflows int64", sc.v)
} }
return int64(sc.v) return int64(sc.v)
} }
@ -723,8 +723,8 @@ func (ev *evaluator) eval(expr Expr) Value {
switch lt, rt := lhs.Type(), rhs.Type(); { switch lt, rt := lhs.Type(), rhs.Type(); {
case lt == ValueTypeScalar && rt == ValueTypeScalar: case lt == ValueTypeScalar && rt == ValueTypeScalar:
return scalar{ return Scalar{
v: scalarBinop(e.Op, lhs.(scalar).v, rhs.(scalar).v), v: ScalarBinop(e.Op, lhs.(Scalar).v, rhs.(Scalar).v),
t: ev.Timestamp, t: ev.Timestamp,
} }
@ -740,10 +740,10 @@ func (ev *evaluator) eval(expr Expr) Value {
return ev.VectorBinop(e.Op, lhs.(Vector), rhs.(Vector), e.VectorMatching, e.ReturnBool) return ev.VectorBinop(e.Op, lhs.(Vector), rhs.(Vector), e.VectorMatching, e.ReturnBool)
} }
case lt == ValueTypeVector && rt == ValueTypeScalar: case lt == ValueTypeVector && rt == ValueTypeScalar:
return ev.VectorScalarBinop(e.Op, lhs.(Vector), rhs.(scalar), false, e.ReturnBool) return ev.VectorScalarBinop(e.Op, lhs.(Vector), rhs.(Scalar), false, e.ReturnBool)
case lt == ValueTypeScalar && rt == ValueTypeVector: case lt == ValueTypeScalar && rt == ValueTypeVector:
return ev.VectorScalarBinop(e.Op, rhs.(Vector), lhs.(scalar), true, e.ReturnBool) return ev.VectorScalarBinop(e.Op, rhs.(Vector), lhs.(Scalar), true, e.ReturnBool)
} }
case *Call: case *Call:
@ -753,7 +753,7 @@ func (ev *evaluator) eval(expr Expr) Value {
return ev.MatrixSelector(e) return ev.MatrixSelector(e)
case *NumberLiteral: case *NumberLiteral:
return scalar{v: e.Val, t: ev.Timestamp} return Scalar{v: e.Val, t: ev.Timestamp}
case *ParenExpr: case *ParenExpr:
return ev.eval(e.Expr) return ev.eval(e.Expr)
@ -766,7 +766,7 @@ func (ev *evaluator) eval(expr Expr) Value {
// Only + and - are possible operators. // Only + and - are possible operators.
if e.Op == itemSUB { if e.Op == itemSUB {
switch v := se.(type) { switch v := se.(type) {
case scalar: case Scalar:
v.v = -v.v v.v = -v.v
case Vector: case Vector:
for i, sv := range v { for i, sv := range v {
@ -1116,8 +1116,8 @@ Outer:
return res return res
} }
// VectorScalarBinop evaluates a binary operation between a Vector and a scalar. // VectorScalarBinop evaluates a binary operation between a Vector and a Scalar.
func (ev *evaluator) VectorScalarBinop(op itemType, lhs Vector, rhs scalar, swap, returnBool bool) Vector { func (ev *evaluator) VectorScalarBinop(op itemType, lhs Vector, rhs Scalar, swap, returnBool bool) Vector {
vec := make(Vector, 0, len(lhs)) vec := make(Vector, 0, len(lhs))
for _, lhsSample := range lhs { for _, lhsSample := range lhs {
@ -1161,8 +1161,8 @@ func copyLabels(metric labels.Labels, withName bool) labels.Labels {
return cm return cm
} }
// scalarBinop evaluates a binary operation between two scalars. // ScalarBinop evaluates a binary operation between two Scalars.
func scalarBinop(op itemType, lhs, rhs float64) float64 { func ScalarBinop(op itemType, lhs, rhs float64) float64 {
switch op { switch op {
case itemADD: case itemADD:
return lhs + rhs return lhs + rhs
@ -1189,7 +1189,7 @@ func scalarBinop(op itemType, lhs, rhs float64) float64 {
case itemLTE: case itemLTE:
return btos(lhs <= rhs) return btos(lhs <= rhs)
} }
panic(fmt.Errorf("operator %q not allowed for scalar operations", op)) panic(fmt.Errorf("operator %q not allowed for Scalar operations", op))
} }
// VectorElemBinop evaluates a binary operation between two Vector elements. // VectorElemBinop evaluates a binary operation between two Vector elements.

View file

@ -36,7 +36,7 @@ type Function struct {
// === time() float64 === // === time() float64 ===
func funcTime(ev *evaluator, args Expressions) Value { func funcTime(ev *evaluator, args Expressions) Value {
return scalar{ return Scalar{
v: float64(ev.Timestamp / 1000), v: float64(ev.Timestamp / 1000),
t: ev.Timestamp, t: ev.Timestamp,
} }
@ -384,24 +384,24 @@ func funcRound(ev *evaluator, args Expressions) Value {
return vec return vec
} }
// === scalar(node ValueTypeVector) Scalar === // === Scalar(node ValueTypeVector) Scalar ===
func funcScalar(ev *evaluator, args Expressions) Value { func funcScalar(ev *evaluator, args Expressions) Value {
v := ev.evalVector(args[0]) v := ev.evalVector(args[0])
if len(v) != 1 { if len(v) != 1 {
return scalar{ return Scalar{
v: math.NaN(), v: math.NaN(),
t: ev.Timestamp, t: ev.Timestamp,
} }
} }
return scalar{ return Scalar{
v: v[0].Value, v: v[0].Value,
t: ev.Timestamp, t: ev.Timestamp,
} }
} }
// === count_scalar(Vector ValueTypeVector) float64 === // === count_Scalar(Vector ValueTypeVector) float64 ===
func funcCountScalar(ev *evaluator, args Expressions) Value { func funcCountScalar(ev *evaluator, args Expressions) Value {
return scalar{ return Scalar{
v: float64(len(ev.evalVector(args[0]))), v: float64(len(ev.evalVector(args[0]))),
t: ev.Timestamp, t: ev.Timestamp,
} }
@ -840,7 +840,7 @@ func funcLabelReplace(ev *evaluator, args Expressions) Value {
return Vector return Vector
} }
// === Vector(s scalar) Vector === // === Vector(s Scalar) Vector ===
func funcVector(ev *evaluator, args Expressions) Value { func funcVector(ev *evaluator, args Expressions) Value {
return Vector{ return Vector{
sample{ sample{
@ -872,49 +872,49 @@ func dateWrapper(ev *evaluator, args Expressions, f func(time.Time) float64) Val
return v return v
} }
// === days_in_month(v Vector) scalar === // === days_in_month(v Vector) Scalar ===
func funcDaysInMonth(ev *evaluator, args Expressions) Value { func funcDaysInMonth(ev *evaluator, args Expressions) Value {
return dateWrapper(ev, args, func(t time.Time) float64 { return dateWrapper(ev, args, func(t time.Time) float64 {
return float64(32 - time.Date(t.Year(), t.Month(), 32, 0, 0, 0, 0, time.UTC).Day()) return float64(32 - time.Date(t.Year(), t.Month(), 32, 0, 0, 0, 0, time.UTC).Day())
}) })
} }
// === day_of_month(v Vector) scalar === // === day_of_month(v Vector) Scalar ===
func funcDayOfMonth(ev *evaluator, args Expressions) Value { func funcDayOfMonth(ev *evaluator, args Expressions) Value {
return dateWrapper(ev, args, func(t time.Time) float64 { return dateWrapper(ev, args, func(t time.Time) float64 {
return float64(t.Day()) return float64(t.Day())
}) })
} }
// === day_of_week(v Vector) scalar === // === day_of_week(v Vector) Scalar ===
func funcDayOfWeek(ev *evaluator, args Expressions) Value { func funcDayOfWeek(ev *evaluator, args Expressions) Value {
return dateWrapper(ev, args, func(t time.Time) float64 { return dateWrapper(ev, args, func(t time.Time) float64 {
return float64(t.Weekday()) return float64(t.Weekday())
}) })
} }
// === hour(v Vector) scalar === // === hour(v Vector) Scalar ===
func funcHour(ev *evaluator, args Expressions) Value { func funcHour(ev *evaluator, args Expressions) Value {
return dateWrapper(ev, args, func(t time.Time) float64 { return dateWrapper(ev, args, func(t time.Time) float64 {
return float64(t.Hour()) return float64(t.Hour())
}) })
} }
// === minute(v Vector) scalar === // === minute(v Vector) Scalar ===
func funcMinute(ev *evaluator, args Expressions) Value { func funcMinute(ev *evaluator, args Expressions) Value {
return dateWrapper(ev, args, func(t time.Time) float64 { return dateWrapper(ev, args, func(t time.Time) float64 {
return float64(t.Minute()) return float64(t.Minute())
}) })
} }
// === month(v Vector) scalar === // === month(v Vector) Scalar ===
func funcMonth(ev *evaluator, args Expressions) Value { func funcMonth(ev *evaluator, args Expressions) Value {
return dateWrapper(ev, args, func(t time.Time) float64 { return dateWrapper(ev, args, func(t time.Time) float64 {
return float64(t.Month()) return float64(t.Month())
}) })
} }
// === year(v Vector) scalar === // === year(v Vector) Scalar ===
func funcYear(ev *evaluator, args Expressions) Value { func funcYear(ev *evaluator, args Expressions) Value {
return dateWrapper(ev, args, func(t time.Time) float64 { return dateWrapper(ev, args, func(t time.Time) float64 {
return float64(t.Year()) return float64(t.Year())
@ -970,8 +970,8 @@ var functions = map[string]*Function{
ReturnType: ValueTypeVector, ReturnType: ValueTypeVector,
Call: funcCountOverTime, Call: funcCountOverTime,
}, },
"count_scalar": { "count_Scalar": {
Name: "count_scalar", Name: "count_Scalar",
ArgTypes: []ValueType{ValueTypeVector}, ArgTypes: []ValueType{ValueTypeVector},
ReturnType: ValueTypeScalar, ReturnType: ValueTypeScalar,
Call: funcCountScalar, Call: funcCountScalar,
@ -1145,8 +1145,8 @@ var functions = map[string]*Function{
ReturnType: ValueTypeVector, ReturnType: ValueTypeVector,
Call: funcRound, Call: funcRound,
}, },
"scalar": { "Scalar": {
Name: "scalar", Name: "Scalar",
ArgTypes: []ValueType{ValueTypeVector}, ArgTypes: []ValueType{ValueTypeVector},
ReturnType: ValueTypeScalar, ReturnType: ValueTypeScalar,
Call: funcScalar, Call: funcScalar,

View file

@ -506,7 +506,7 @@ func (p *parser) balance(lhs Expr, op itemType, rhs Expr, vecMatching *VectorMat
if (precd < 0) || (precd == 0 && op.isRightAssociative()) { if (precd < 0) || (precd == 0 && op.isRightAssociative()) {
balanced := p.balance(lhsBE.RHS, op, rhs, vecMatching, returnBool) balanced := p.balance(lhsBE.RHS, op, rhs, vecMatching, returnBool)
if lhsBE.Op.isComparisonOperator() && !lhsBE.ReturnBool && balanced.Type() == ValueTypeScalar && lhsBE.LHS.Type() == ValueTypeScalar { if lhsBE.Op.isComparisonOperator() && !lhsBE.ReturnBool && balanced.Type() == ValueTypeScalar && lhsBE.LHS.Type() == ValueTypeScalar {
p.errorf("comparisons between scalars must use BOOL modifier") p.errorf("comparisons between Scalars must use BOOL modifier")
} }
return &BinaryExpr{ return &BinaryExpr{
Op: lhsBE.Op, Op: lhsBE.Op,
@ -518,7 +518,7 @@ func (p *parser) balance(lhs Expr, op itemType, rhs Expr, vecMatching *VectorMat
} }
} }
if op.isComparisonOperator() && !returnBool && rhs.Type() == ValueTypeScalar && lhs.Type() == ValueTypeScalar { if op.isComparisonOperator() && !returnBool && rhs.Type() == ValueTypeScalar && lhs.Type() == ValueTypeScalar {
p.errorf("comparisons between scalars must use BOOL modifier") p.errorf("comparisons between Scalars must use BOOL modifier")
} }
return &BinaryExpr{ return &BinaryExpr{
Op: op, Op: op,
@ -1028,7 +1028,7 @@ func (p *parser) checkType(node Node) (typ ValueType) {
case *RecordStmt: case *RecordStmt:
ty := p.checkType(n.Expr) ty := p.checkType(n.Expr)
if ty != ValueTypeVector && ty != ValueTypeScalar { if ty != ValueTypeVector && ty != ValueTypeScalar {
p.errorf("record statement must have a valid expression of type instant Vector or scalar but got %s", documentedType(ty)) p.errorf("record statement must have a valid expression of type instant Vector or Scalar but got %s", documentedType(ty))
} }
case Expressions: case Expressions:
@ -1058,7 +1058,7 @@ func (p *parser) checkType(node Node) (typ ValueType) {
p.errorf("binary expression does not support operator %q", n.Op) p.errorf("binary expression does not support operator %q", n.Op)
} }
if (lt != ValueTypeScalar && lt != ValueTypeVector) || (rt != ValueTypeScalar && rt != ValueTypeVector) { if (lt != ValueTypeScalar && lt != ValueTypeVector) || (rt != ValueTypeScalar && rt != ValueTypeVector) {
p.errorf("binary expression must contain only scalar and instant Vector types") p.errorf("binary expression must contain only Scalar and instant Vector types")
} }
if (lt != ValueTypeVector || rt != ValueTypeVector) && n.VectorMatching != nil { if (lt != ValueTypeVector || rt != ValueTypeVector) && n.VectorMatching != nil {
@ -1079,7 +1079,7 @@ func (p *parser) checkType(node Node) (typ ValueType) {
} }
if (lt == ValueTypeScalar || rt == ValueTypeScalar) && n.Op.isSetOperator() { if (lt == ValueTypeScalar || rt == ValueTypeScalar) && n.Op.isSetOperator() {
p.errorf("set operator %q not allowed in binary scalar expression", n.Op) p.errorf("set operator %q not allowed in binary Scalar expression", n.Op)
} }
case *Call: case *Call:
@ -1102,7 +1102,7 @@ func (p *parser) checkType(node Node) (typ ValueType) {
p.errorf("only + and - operators allowed for unary expressions") p.errorf("only + and - operators allowed for unary expressions")
} }
if t := p.checkType(n.Expr); t != ValueTypeScalar && t != ValueTypeVector { if t := p.checkType(n.Expr); t != ValueTypeScalar && t != ValueTypeVector {
p.errorf("unary expression only allowed on expressions of type scalar or instant Vector, got %q", documentedType(t)) p.errorf("unary expression only allowed on expressions of type Scalar or instant Vector, got %q", documentedType(t))
} }
case *NumberLiteral, *MatrixSelector, *StringLiteral, *VectorSelector: case *NumberLiteral, *MatrixSelector, *StringLiteral, *VectorSelector:

View file

@ -404,9 +404,9 @@ func (ev *evalCmd) compareResult(result Value) error {
} }
} }
case scalar: case Scalar:
if !almostEqual(ev.expected[0].vals[0].value, val.v) { if !almostEqual(ev.expected[0].vals[0].value, val.v) {
return fmt.Errorf("expected scalar %v but got %v", val.v, ev.expected[0].vals[0].value) return fmt.Errorf("expected Scalar %v but got %v", val.v, ev.expected[0].vals[0].value)
} }
default: default:

View file

@ -21,6 +21,7 @@ import (
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
"time"
html_template "html/template" html_template "html/template"
text_template "text/template" text_template "text/template"
@ -56,8 +57,8 @@ func (q queryResultByLabelSorter) Swap(i, j int) {
q.results[i], q.results[j] = q.results[j], q.results[i] q.results[i], q.results[j] = q.results[j], q.results[i]
} }
func query(ctx context.Context, q string, timestamp model.Time, queryEngine *promql.Engine) (queryResult, error) { func query(ctx context.Context, q string, ts time.Time, queryEngine *promql.Engine) (queryResult, error) {
query, err := queryEngine.NewInstantQuery(q, timestamp) query, err := queryEngine.NewInstantQuery(q, ts)
if err != nil { if err != nil {
return nil, err return nil, err
} }