github.com/influxdata/influxdb/v2@v2.7.6/influxql/query/compile.go (about) 1 package query 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "strings" 8 "time" 9 10 "github.com/influxdata/influxdb/v2/models" 11 "github.com/influxdata/influxql" 12 ) 13 14 // CompileOptions are the customization options for the compiler. 15 type CompileOptions struct { 16 Now time.Time 17 } 18 19 // Statement is a compiled query statement. 20 type Statement interface { 21 // Prepare prepares the statement by mapping shards and finishing the creation 22 // of the query plan. 23 Prepare(ctx context.Context, shardMapper ShardMapper, opt SelectOptions) (PreparedStatement, error) 24 } 25 26 // compiledStatement represents a select statement that has undergone some initial processing to 27 // determine if it is valid and to have some initial modifications done on the AST. 28 type compiledStatement struct { 29 // Condition is the condition used for accessing data. 30 Condition influxql.Expr 31 32 // TimeRange is the TimeRange for selecting data. 33 TimeRange influxql.TimeRange 34 35 // Interval holds the time grouping interval. 36 Interval Interval 37 38 // InheritedInterval marks if the interval was inherited by a parent. 39 // If this is set, then an interval that was inherited will not cause 40 // a query that shouldn't have an interval to fail. 41 InheritedInterval bool 42 43 // ExtraIntervals is the number of extra intervals that will be read in addition 44 // to the TimeRange. It is a multiple of Interval and only applies to queries that 45 // have an Interval. It is used to extend the TimeRange of the mapped shards to 46 // include additional non-emitted intervals used by derivative and other functions. 47 // It will be set to the highest number of extra intervals that need to be read even 48 // if it doesn't apply to all functions. The number will always be positive. 49 // This value may be set to a non-zero value even if there is no interval for the 50 // compiled query. 51 ExtraIntervals int 52 53 // Ascending is true if the time ordering is ascending. 54 Ascending bool 55 56 // FunctionCalls holds a reference to the call expression of every function 57 // call that has been encountered. 58 FunctionCalls []*influxql.Call 59 60 // OnlySelectors is set to true when there are no aggregate functions. 61 OnlySelectors bool 62 63 // HasDistinct is set when the distinct() function is encountered. 64 HasDistinct bool 65 66 // FillOption contains the fill option for aggregates. 67 FillOption influxql.FillOption 68 69 // TopBottomFunction is set to top or bottom when one of those functions are 70 // used in the statement. 71 TopBottomFunction string 72 73 // HasAuxiliaryFields is true when the function requires auxiliary fields. 74 HasAuxiliaryFields bool 75 76 // Fields holds all of the fields that will be used. 77 Fields []*compiledField 78 79 // TimeFieldName stores the name of the time field's column. 80 // The column names generated by the compiler will not conflict with 81 // this name. 82 TimeFieldName string 83 84 // Limit is the number of rows per series this query should be limited to. 85 Limit int 86 87 // HasTarget is true if this query is being written into a target. 88 HasTarget bool 89 90 // Options holds the configured compiler options. 91 Options CompileOptions 92 93 stmt *influxql.SelectStatement 94 } 95 96 func newCompiler(opt CompileOptions) *compiledStatement { 97 if opt.Now.IsZero() { 98 opt.Now = time.Now().UTC() 99 } 100 return &compiledStatement{ 101 OnlySelectors: true, 102 TimeFieldName: "time", 103 Options: opt, 104 } 105 } 106 107 func Compile(stmt *influxql.SelectStatement, opt CompileOptions) (_ Statement, err error) { 108 c := newCompiler(opt) 109 c.stmt = stmt.Clone() 110 if err := c.preprocess(c.stmt); err != nil { 111 return nil, err 112 } 113 if err := c.compile(c.stmt); err != nil { 114 return nil, err 115 } 116 c.stmt.TimeAlias = c.TimeFieldName 117 c.stmt.Condition = c.Condition 118 119 defer func() { 120 if e := recover(); e != nil && err == nil { 121 var ok bool 122 err, ok = e.(error) 123 if !ok { 124 err = fmt.Errorf("panic: %v", e) 125 } 126 err = fmt.Errorf("likely malformed statement, unable to rewrite: %w", err) 127 } 128 }() 129 130 // Convert DISTINCT into a call. 131 c.stmt.RewriteDistinct() 132 133 // Remove "time" from fields list. 134 c.stmt.RewriteTimeFields() 135 136 // Rewrite any regex conditions that could make use of the index. 137 c.stmt.RewriteRegexConditions() 138 return c, nil 139 } 140 141 // preprocess retrieves and records the global attributes of the current statement. 142 func (c *compiledStatement) preprocess(stmt *influxql.SelectStatement) error { 143 c.Ascending = stmt.TimeAscending() 144 c.Limit = stmt.Limit 145 c.HasTarget = stmt.Target != nil 146 147 valuer := influxql.NowValuer{Now: c.Options.Now, Location: stmt.Location} 148 cond, t, err := influxql.ConditionExpr(stmt.Condition, &valuer) 149 if err != nil { 150 return err 151 } 152 // Verify that the condition is actually ok to use. 153 if err := c.validateCondition(cond); err != nil { 154 return err 155 } 156 c.Condition = cond 157 c.TimeRange = t 158 159 // Read the dimensions of the query, validate them, and retrieve the interval 160 // if it exists. 161 if err := c.compileDimensions(stmt); err != nil { 162 return err 163 } 164 165 // Retrieve the fill option for the statement. 166 c.FillOption = stmt.Fill 167 168 // Resolve the min and max times now that we know if there is an interval or not. 169 if c.TimeRange.Min.IsZero() { 170 c.TimeRange.Min = time.Unix(0, influxql.MinTime).UTC() 171 } 172 if c.TimeRange.Max.IsZero() { 173 // If the interval is non-zero, then we have an aggregate query and 174 // need to limit the maximum time to now() for backwards compatibility 175 // and usability. 176 if !c.Interval.IsZero() { 177 c.TimeRange.Max = c.Options.Now 178 } else { 179 c.TimeRange.Max = time.Unix(0, influxql.MaxTime).UTC() 180 } 181 } 182 return nil 183 } 184 185 func (c *compiledStatement) compile(stmt *influxql.SelectStatement) error { 186 if err := c.compileFields(stmt); err != nil { 187 return err 188 } 189 if err := c.validateFields(); err != nil { 190 return err 191 } 192 193 // Look through the sources and compile each of the subqueries (if they exist). 194 // We do this after compiling the outside because subqueries may require 195 // inherited state. 196 for _, source := range stmt.Sources { 197 switch source := source.(type) { 198 case *influxql.SubQuery: 199 source.Statement.OmitTime = true 200 if err := c.subquery(source.Statement); err != nil { 201 return err 202 } 203 source.Statement.RewriteRegexConditions() 204 } 205 } 206 return nil 207 } 208 209 func (c *compiledStatement) compileFields(stmt *influxql.SelectStatement) error { 210 valuer := MathValuer{} 211 212 c.Fields = make([]*compiledField, 0, len(stmt.Fields)) 213 for _, f := range stmt.Fields { 214 // Remove any time selection (it is automatically selected by default) 215 // and set the time column name to the alias of the time field if it exists. 216 // Such as SELECT time, max(value) FROM cpu will be SELECT max(value) FROM cpu 217 // and SELECT time AS timestamp, max(value) FROM cpu will return "timestamp" 218 // as the column name for the time. 219 if ref, ok := f.Expr.(*influxql.VarRef); ok && ref.Val == "time" { 220 if f.Alias != "" { 221 c.TimeFieldName = f.Alias 222 } 223 continue 224 } 225 226 // Append this field to the list of processed fields and compile it. 227 f.Expr = influxql.Reduce(f.Expr, &valuer) 228 field := &compiledField{ 229 global: c, 230 Field: f, 231 AllowWildcard: true, 232 } 233 c.Fields = append(c.Fields, field) 234 if err := field.compileExpr(field.Field.Expr); err != nil { 235 return err 236 } 237 } 238 return nil 239 } 240 241 type compiledField struct { 242 // This holds the global state from the compiled statement. 243 global *compiledStatement 244 245 // Field is the top level field that is being compiled. 246 Field *influxql.Field 247 248 // AllowWildcard is set to true if a wildcard or regular expression is allowed. 249 AllowWildcard bool 250 } 251 252 // compileExpr creates the node that executes the expression and connects that 253 // node to the WriteEdge as the output. 254 func (c *compiledField) compileExpr(expr influxql.Expr) error { 255 switch expr := expr.(type) { 256 case *influxql.VarRef: 257 // A bare variable reference will require auxiliary fields. 258 c.global.HasAuxiliaryFields = true 259 return nil 260 case *influxql.Wildcard: 261 // Wildcards use auxiliary fields. We assume there will be at least one 262 // expansion. 263 c.global.HasAuxiliaryFields = true 264 if !c.AllowWildcard { 265 return errors.New("unable to use wildcard in a binary expression") 266 } 267 return nil 268 case *influxql.RegexLiteral: 269 if !c.AllowWildcard { 270 return errors.New("unable to use regex in a binary expression") 271 } 272 c.global.HasAuxiliaryFields = true 273 return nil 274 case *influxql.Call: 275 if isMathFunction(expr) { 276 return c.compileMathFunction(expr) 277 } 278 279 // Register the function call in the list of function calls. 280 c.global.FunctionCalls = append(c.global.FunctionCalls, expr) 281 282 switch expr.Name { 283 case "percentile": 284 return c.compilePercentile(expr.Args) 285 case "sample": 286 return c.compileSample(expr.Args) 287 case "distinct": 288 return c.compileDistinct(expr.Args, false) 289 case "top", "bottom": 290 return c.compileTopBottom(expr) 291 case "derivative", "non_negative_derivative": 292 isNonNegative := expr.Name == "non_negative_derivative" 293 return c.compileDerivative(expr.Args, isNonNegative) 294 case "difference", "non_negative_difference": 295 isNonNegative := expr.Name == "non_negative_difference" 296 return c.compileDifference(expr.Args, isNonNegative) 297 case "cumulative_sum": 298 return c.compileCumulativeSum(expr.Args) 299 case "moving_average": 300 return c.compileMovingAverage(expr.Args) 301 case "exponential_moving_average", "double_exponential_moving_average", "triple_exponential_moving_average", "relative_strength_index", "triple_exponential_derivative": 302 return c.compileExponentialMovingAverage(expr.Name, expr.Args) 303 case "kaufmans_efficiency_ratio", "kaufmans_adaptive_moving_average": 304 return c.compileKaufmans(expr.Name, expr.Args) 305 case "chande_momentum_oscillator": 306 return c.compileChandeMomentumOscillator(expr.Args) 307 case "elapsed": 308 return c.compileElapsed(expr.Args) 309 case "integral": 310 return c.compileIntegral(expr.Args) 311 case "count_hll": 312 return c.compileCountHll(expr.Args) 313 case "holt_winters", "holt_winters_with_fit": 314 withFit := expr.Name == "holt_winters_with_fit" 315 return c.compileHoltWinters(expr.Args, withFit) 316 default: 317 return c.compileFunction(expr) 318 } 319 case *influxql.Distinct: 320 call := expr.NewCall() 321 c.global.FunctionCalls = append(c.global.FunctionCalls, call) 322 return c.compileDistinct(call.Args, false) 323 case *influxql.BinaryExpr: 324 // Disallow wildcards in binary expressions. RewriteFields, which expands 325 // wildcards, is too complicated if we allow wildcards inside of expressions. 326 c.AllowWildcard = false 327 328 // Check if either side is a literal so we only compile one side if it is. 329 if _, ok := expr.LHS.(influxql.Literal); ok { 330 if _, ok := expr.RHS.(influxql.Literal); ok { 331 return errors.New("cannot perform a binary expression on two literals") 332 } 333 return c.compileExpr(expr.RHS) 334 } else if _, ok := expr.RHS.(influxql.Literal); ok { 335 return c.compileExpr(expr.LHS) 336 } else { 337 // Validate both sides of the expression. 338 if err := c.compileExpr(expr.LHS); err != nil { 339 return err 340 } 341 if err := c.compileExpr(expr.RHS); err != nil { 342 return err 343 } 344 return nil 345 } 346 case *influxql.ParenExpr: 347 return c.compileExpr(expr.Expr) 348 case influxql.Literal: 349 return errors.New("field must contain at least one variable") 350 } 351 return errors.New("unimplemented") 352 } 353 354 // compileNestedExpr ensures that the expression is compiled as if it were 355 // a nested expression. 356 func (c *compiledField) compileNestedExpr(expr influxql.Expr) error { 357 // Intercept the distinct call so we can pass nested as true. 358 switch expr := expr.(type) { 359 case *influxql.Call: 360 if expr.Name == "distinct" { 361 return c.compileDistinct(expr.Args, true) 362 } 363 case *influxql.Distinct: 364 call := expr.NewCall() 365 return c.compileDistinct(call.Args, true) 366 } 367 return c.compileExpr(expr) 368 } 369 370 func (c *compiledField) compileSymbol(name string, field influxql.Expr) error { 371 // Must be a variable reference, wildcard, or regexp. 372 switch field.(type) { 373 case *influxql.VarRef: 374 return nil 375 case *influxql.Wildcard: 376 if !c.AllowWildcard { 377 return fmt.Errorf("unsupported expression with wildcard: %s()", name) 378 } 379 c.global.OnlySelectors = false 380 return nil 381 case *influxql.RegexLiteral: 382 if !c.AllowWildcard { 383 return fmt.Errorf("unsupported expression with regex field: %s()", name) 384 } 385 c.global.OnlySelectors = false 386 return nil 387 default: 388 return fmt.Errorf("expected field argument in %s()", name) 389 } 390 } 391 392 func (c *compiledField) compileFunction(expr *influxql.Call) error { 393 // Validate the function call and mark down some meta properties 394 // related to the function for query validation. 395 switch expr.Name { 396 case "max", "min", "first", "last": 397 // top/bottom are not included here since they are not typical functions. 398 case "count", "sum", "mean", "median", "mode", "stddev", "spread", "sum_hll": 399 // These functions are not considered selectors. 400 c.global.OnlySelectors = false 401 default: 402 return fmt.Errorf("undefined function %s()", expr.Name) 403 } 404 405 if exp, got := 1, len(expr.Args); exp != got { 406 return fmt.Errorf("invalid number of arguments for %s, expected %d, got %d", expr.Name, exp, got) 407 } 408 409 // If this is a call to count(), allow distinct() to be used as the function argument. 410 if expr.Name == "count" { 411 // If we have count(), the argument may be a distinct() call. 412 if arg0, ok := expr.Args[0].(*influxql.Call); ok && arg0.Name == "distinct" { 413 return c.compileDistinct(arg0.Args, true) 414 } else if arg0, ok := expr.Args[0].(*influxql.Distinct); ok { 415 call := arg0.NewCall() 416 return c.compileDistinct(call.Args, true) 417 } 418 } 419 return c.compileSymbol(expr.Name, expr.Args[0]) 420 } 421 422 func (c *compiledField) compilePercentile(args []influxql.Expr) error { 423 if exp, got := 2, len(args); got != exp { 424 return fmt.Errorf("invalid number of arguments for percentile, expected %d, got %d", exp, got) 425 } 426 427 switch args[1].(type) { 428 case *influxql.IntegerLiteral: 429 case *influxql.NumberLiteral: 430 default: 431 return fmt.Errorf("expected float argument in percentile()") 432 } 433 return c.compileSymbol("percentile", args[0]) 434 } 435 436 func (c *compiledField) compileSample(args []influxql.Expr) error { 437 if exp, got := 2, len(args); got != exp { 438 return fmt.Errorf("invalid number of arguments for sample, expected %d, got %d", exp, got) 439 } 440 441 switch arg1 := args[1].(type) { 442 case *influxql.IntegerLiteral: 443 if arg1.Val <= 0 { 444 return fmt.Errorf("sample window must be greater than 1, got %d", arg1.Val) 445 } 446 default: 447 return fmt.Errorf("expected integer argument in sample()") 448 } 449 return c.compileSymbol("sample", args[0]) 450 } 451 452 func (c *compiledField) compileDerivative(args []influxql.Expr, isNonNegative bool) error { 453 name := "derivative" 454 if isNonNegative { 455 name = "non_negative_derivative" 456 } 457 458 if min, max, got := 1, 2, len(args); got > max || got < min { 459 return fmt.Errorf("invalid number of arguments for %s, expected at least %d but no more than %d, got %d", name, min, max, got) 460 } 461 462 // Retrieve the duration from the derivative() call, if specified. 463 if len(args) == 2 { 464 switch arg1 := args[1].(type) { 465 case *influxql.DurationLiteral: 466 if arg1.Val <= 0 { 467 return fmt.Errorf("duration argument must be positive, got %s", influxql.FormatDuration(arg1.Val)) 468 } 469 default: 470 return fmt.Errorf("second argument to %s must be a duration, got %T", name, args[1]) 471 } 472 } 473 c.global.OnlySelectors = false 474 if c.global.ExtraIntervals < 1 { 475 c.global.ExtraIntervals = 1 476 } 477 478 // Must be a variable reference, function, wildcard, or regexp. 479 switch arg0 := args[0].(type) { 480 case *influxql.Call: 481 if c.global.Interval.IsZero() { 482 return fmt.Errorf("%s aggregate requires a GROUP BY interval", name) 483 } 484 return c.compileNestedExpr(arg0) 485 default: 486 if !c.global.Interval.IsZero() && !c.global.InheritedInterval { 487 return fmt.Errorf("aggregate function required inside the call to %s", name) 488 } 489 return c.compileSymbol(name, arg0) 490 } 491 } 492 493 func (c *compiledField) compileElapsed(args []influxql.Expr) error { 494 if min, max, got := 1, 2, len(args); got > max || got < min { 495 return fmt.Errorf("invalid number of arguments for elapsed, expected at least %d but no more than %d, got %d", min, max, got) 496 } 497 498 // Retrieve the duration from the elapsed() call, if specified. 499 if len(args) == 2 { 500 switch arg1 := args[1].(type) { 501 case *influxql.DurationLiteral: 502 if arg1.Val <= 0 { 503 return fmt.Errorf("duration argument must be positive, got %s", influxql.FormatDuration(arg1.Val)) 504 } 505 default: 506 return fmt.Errorf("second argument to elapsed must be a duration, got %T", args[1]) 507 } 508 } 509 c.global.OnlySelectors = false 510 if c.global.ExtraIntervals < 1 { 511 c.global.ExtraIntervals = 1 512 } 513 514 // Must be a variable reference, function, wildcard, or regexp. 515 switch arg0 := args[0].(type) { 516 case *influxql.Call: 517 if c.global.Interval.IsZero() { 518 return fmt.Errorf("elapsed aggregate requires a GROUP BY interval") 519 } 520 return c.compileNestedExpr(arg0) 521 default: 522 if !c.global.Interval.IsZero() && !c.global.InheritedInterval { 523 return fmt.Errorf("aggregate function required inside the call to elapsed") 524 } 525 return c.compileSymbol("elapsed", arg0) 526 } 527 } 528 529 func (c *compiledField) compileDifference(args []influxql.Expr, isNonNegative bool) error { 530 name := "difference" 531 if isNonNegative { 532 name = "non_negative_difference" 533 } 534 535 if got := len(args); got != 1 { 536 return fmt.Errorf("invalid number of arguments for %s, expected 1, got %d", name, got) 537 } 538 c.global.OnlySelectors = false 539 if c.global.ExtraIntervals < 1 { 540 c.global.ExtraIntervals = 1 541 } 542 543 // Must be a variable reference, function, wildcard, or regexp. 544 switch arg0 := args[0].(type) { 545 case *influxql.Call: 546 if c.global.Interval.IsZero() { 547 return fmt.Errorf("%s aggregate requires a GROUP BY interval", name) 548 } 549 return c.compileNestedExpr(arg0) 550 default: 551 if !c.global.Interval.IsZero() && !c.global.InheritedInterval { 552 return fmt.Errorf("aggregate function required inside the call to %s", name) 553 } 554 return c.compileSymbol(name, arg0) 555 } 556 } 557 558 func (c *compiledField) compileCumulativeSum(args []influxql.Expr) error { 559 if got := len(args); got != 1 { 560 return fmt.Errorf("invalid number of arguments for cumulative_sum, expected 1, got %d", got) 561 } 562 c.global.OnlySelectors = false 563 if c.global.ExtraIntervals < 1 { 564 c.global.ExtraIntervals = 1 565 } 566 567 // Must be a variable reference, function, wildcard, or regexp. 568 switch arg0 := args[0].(type) { 569 case *influxql.Call: 570 if c.global.Interval.IsZero() { 571 return fmt.Errorf("cumulative_sum aggregate requires a GROUP BY interval") 572 } 573 return c.compileNestedExpr(arg0) 574 default: 575 if !c.global.Interval.IsZero() && !c.global.InheritedInterval { 576 return fmt.Errorf("aggregate function required inside the call to cumulative_sum") 577 } 578 return c.compileSymbol("cumulative_sum", arg0) 579 } 580 } 581 582 func (c *compiledField) compileMovingAverage(args []influxql.Expr) error { 583 if got := len(args); got != 2 { 584 return fmt.Errorf("invalid number of arguments for moving_average, expected 2, got %d", got) 585 } 586 587 arg1, ok := args[1].(*influxql.IntegerLiteral) 588 if !ok { 589 return fmt.Errorf("second argument for moving_average must be an integer, got %T", args[1]) 590 } else if arg1.Val <= 1 { 591 return fmt.Errorf("moving_average window must be greater than 1, got %d", arg1.Val) 592 } 593 c.global.OnlySelectors = false 594 if c.global.ExtraIntervals < int(arg1.Val) { 595 c.global.ExtraIntervals = int(arg1.Val) 596 } 597 598 // Must be a variable reference, function, wildcard, or regexp. 599 switch arg0 := args[0].(type) { 600 case *influxql.Call: 601 if c.global.Interval.IsZero() { 602 return fmt.Errorf("moving_average aggregate requires a GROUP BY interval") 603 } 604 return c.compileNestedExpr(arg0) 605 default: 606 if !c.global.Interval.IsZero() && !c.global.InheritedInterval { 607 return fmt.Errorf("aggregate function required inside the call to moving_average") 608 } 609 return c.compileSymbol("moving_average", arg0) 610 } 611 } 612 613 func (c *compiledField) compileExponentialMovingAverage(name string, args []influxql.Expr) error { 614 if got := len(args); got < 2 || got > 4 { 615 return fmt.Errorf("invalid number of arguments for %s, expected at least 2 but no more than 4, got %d", name, got) 616 } 617 618 arg1, ok := args[1].(*influxql.IntegerLiteral) 619 if !ok { 620 return fmt.Errorf("%s period must be an integer", name) 621 } else if arg1.Val < 1 { 622 return fmt.Errorf("%s period must be greater than or equal to 1", name) 623 } 624 625 if len(args) >= 3 { 626 switch arg2 := args[2].(type) { 627 case *influxql.IntegerLiteral: 628 if name == "triple_exponential_derivative" && arg2.Val < 1 && arg2.Val != -1 { 629 return fmt.Errorf("%s hold period must be greater than or equal to 1", name) 630 } 631 if arg2.Val < 0 && arg2.Val != -1 { 632 return fmt.Errorf("%s hold period must be greater than or equal to 0", name) 633 } 634 default: 635 return fmt.Errorf("%s hold period must be an integer", name) 636 } 637 } 638 639 if len(args) >= 4 { 640 switch arg3 := args[3].(type) { 641 case *influxql.StringLiteral: 642 switch arg3.Val { 643 case "exponential", "simple": 644 default: 645 return fmt.Errorf("%s warmup type must be one of: 'exponential' 'simple'", name) 646 } 647 default: 648 return fmt.Errorf("%s warmup type must be a string", name) 649 } 650 } 651 652 c.global.OnlySelectors = false 653 if c.global.ExtraIntervals < int(arg1.Val) { 654 c.global.ExtraIntervals = int(arg1.Val) 655 } 656 657 switch arg0 := args[0].(type) { 658 case *influxql.Call: 659 if c.global.Interval.IsZero() { 660 return fmt.Errorf("%s aggregate requires a GROUP BY interval", name) 661 } 662 return c.compileExpr(arg0) 663 default: 664 if !c.global.Interval.IsZero() && !c.global.InheritedInterval { 665 return fmt.Errorf("aggregate function required inside the call to %s", name) 666 } 667 return c.compileSymbol(name, arg0) 668 } 669 } 670 671 func (c *compiledField) compileKaufmans(name string, args []influxql.Expr) error { 672 if got := len(args); got < 2 || got > 3 { 673 return fmt.Errorf("invalid number of arguments for %s, expected at least 2 but no more than 3, got %d", name, got) 674 } 675 676 arg1, ok := args[1].(*influxql.IntegerLiteral) 677 if !ok { 678 return fmt.Errorf("%s period must be an integer", name) 679 } else if arg1.Val < 1 { 680 return fmt.Errorf("%s period must be greater than or equal to 1", name) 681 } 682 683 if len(args) >= 3 { 684 switch arg2 := args[2].(type) { 685 case *influxql.IntegerLiteral: 686 if arg2.Val < 0 && arg2.Val != -1 { 687 return fmt.Errorf("%s hold period must be greater than or equal to 0", name) 688 } 689 default: 690 return fmt.Errorf("%s hold period must be an integer", name) 691 } 692 } 693 694 c.global.OnlySelectors = false 695 if c.global.ExtraIntervals < int(arg1.Val) { 696 c.global.ExtraIntervals = int(arg1.Val) 697 } 698 699 switch arg0 := args[0].(type) { 700 case *influxql.Call: 701 if c.global.Interval.IsZero() { 702 return fmt.Errorf("%s aggregate requires a GROUP BY interval", name) 703 } 704 return c.compileExpr(arg0) 705 default: 706 if !c.global.Interval.IsZero() && !c.global.InheritedInterval { 707 return fmt.Errorf("aggregate function required inside the call to %s", name) 708 } 709 return c.compileSymbol(name, arg0) 710 } 711 } 712 713 func (c *compiledField) compileChandeMomentumOscillator(args []influxql.Expr) error { 714 if got := len(args); got < 2 || got > 4 { 715 return fmt.Errorf("invalid number of arguments for chande_momentum_oscillator, expected at least 2 but no more than 4, got %d", got) 716 } 717 718 arg1, ok := args[1].(*influxql.IntegerLiteral) 719 if !ok { 720 return fmt.Errorf("chande_momentum_oscillator period must be an integer") 721 } else if arg1.Val < 1 { 722 return fmt.Errorf("chande_momentum_oscillator period must be greater than or equal to 1") 723 } 724 725 if len(args) >= 3 { 726 switch arg2 := args[2].(type) { 727 case *influxql.IntegerLiteral: 728 if arg2.Val < 0 && arg2.Val != -1 { 729 return fmt.Errorf("chande_momentum_oscillator hold period must be greater than or equal to 0") 730 } 731 default: 732 return fmt.Errorf("chande_momentum_oscillator hold period must be an integer") 733 } 734 } 735 736 c.global.OnlySelectors = false 737 if c.global.ExtraIntervals < int(arg1.Val) { 738 c.global.ExtraIntervals = int(arg1.Val) 739 } 740 741 if len(args) >= 4 { 742 switch arg3 := args[3].(type) { 743 case *influxql.StringLiteral: 744 switch arg3.Val { 745 case "none", "exponential", "simple": 746 default: 747 return fmt.Errorf("chande_momentum_oscillator warmup type must be one of: 'none' 'exponential' 'simple'") 748 } 749 default: 750 return fmt.Errorf("chande_momentum_oscillator warmup type must be a string") 751 } 752 } 753 754 switch arg0 := args[0].(type) { 755 case *influxql.Call: 756 if c.global.Interval.IsZero() { 757 return fmt.Errorf("chande_momentum_oscillator aggregate requires a GROUP BY interval") 758 } 759 return c.compileExpr(arg0) 760 default: 761 if !c.global.Interval.IsZero() && !c.global.InheritedInterval { 762 return fmt.Errorf("aggregate function required inside the call to chande_momentum_oscillator") 763 } 764 return c.compileSymbol("chande_momentum_oscillator", arg0) 765 } 766 } 767 768 func (c *compiledField) compileIntegral(args []influxql.Expr) error { 769 if min, max, got := 1, 2, len(args); got > max || got < min { 770 return fmt.Errorf("invalid number of arguments for integral, expected at least %d but no more than %d, got %d", min, max, got) 771 } 772 773 if len(args) == 2 { 774 switch arg1 := args[1].(type) { 775 case *influxql.DurationLiteral: 776 if arg1.Val <= 0 { 777 return fmt.Errorf("duration argument must be positive, got %s", influxql.FormatDuration(arg1.Val)) 778 } 779 default: 780 return errors.New("second argument must be a duration") 781 } 782 } 783 c.global.OnlySelectors = false 784 785 // Must be a variable reference, wildcard, or regexp. 786 return c.compileSymbol("integral", args[0]) 787 } 788 789 func (c *compiledField) compileCountHll(args []influxql.Expr) error { 790 if exp, got := 1, len(args); exp != got { 791 return fmt.Errorf("invalid number of arguments for count_hll, expected %d, got %d", exp, got) 792 } 793 c.global.OnlySelectors = false 794 switch arg0 := args[0].(type) { 795 case *influxql.Call: 796 return c.compileExpr(arg0) 797 default: 798 return c.compileSymbol("count_hll", arg0) 799 } 800 } 801 802 func (c *compiledField) compileHoltWinters(args []influxql.Expr, withFit bool) error { 803 name := "holt_winters" 804 if withFit { 805 name = "holt_winters_with_fit" 806 } 807 808 if exp, got := 3, len(args); got != exp { 809 return fmt.Errorf("invalid number of arguments for %s, expected %d, got %d", name, exp, got) 810 } 811 812 n, ok := args[1].(*influxql.IntegerLiteral) 813 if !ok { 814 return fmt.Errorf("expected integer argument as second arg in %s", name) 815 } else if n.Val <= 0 { 816 return fmt.Errorf("second arg to %s must be greater than 0, got %d", name, n.Val) 817 } 818 819 s, ok := args[2].(*influxql.IntegerLiteral) 820 if !ok { 821 return fmt.Errorf("expected integer argument as third arg in %s", name) 822 } else if s.Val < 0 { 823 return fmt.Errorf("third arg to %s cannot be negative, got %d", name, s.Val) 824 } 825 c.global.OnlySelectors = false 826 827 call, ok := args[0].(*influxql.Call) 828 if !ok { 829 return fmt.Errorf("must use aggregate function with %s", name) 830 } else if c.global.Interval.IsZero() { 831 return fmt.Errorf("%s aggregate requires a GROUP BY interval", name) 832 } 833 return c.compileNestedExpr(call) 834 } 835 836 func (c *compiledField) compileDistinct(args []influxql.Expr, nested bool) error { 837 if len(args) == 0 { 838 return errors.New("distinct function requires at least one argument") 839 } else if len(args) != 1 { 840 return errors.New("distinct function can only have one argument") 841 } 842 843 if _, ok := args[0].(*influxql.VarRef); !ok { 844 return errors.New("expected field argument in distinct()") 845 } 846 if !nested { 847 c.global.HasDistinct = true 848 } 849 c.global.OnlySelectors = false 850 return nil 851 } 852 853 func (c *compiledField) compileTopBottom(call *influxql.Call) error { 854 if c.global.TopBottomFunction != "" { 855 return fmt.Errorf("selector function %s() cannot be combined with other functions", c.global.TopBottomFunction) 856 } 857 858 if exp, got := 2, len(call.Args); got < exp { 859 return fmt.Errorf("invalid number of arguments for %s, expected at least %d, got %d", call.Name, exp, got) 860 } 861 862 limit, ok := call.Args[len(call.Args)-1].(*influxql.IntegerLiteral) 863 if !ok { 864 return fmt.Errorf("expected integer as last argument in %s(), found %s", call.Name, call.Args[len(call.Args)-1]) 865 } else if limit.Val <= 0 { 866 return fmt.Errorf("limit (%d) in %s function must be at least 1", limit.Val, call.Name) 867 } else if c.global.Limit > 0 && int(limit.Val) > c.global.Limit { 868 return fmt.Errorf("limit (%d) in %s function can not be larger than the LIMIT (%d) in the select statement", limit.Val, call.Name, c.global.Limit) 869 } 870 871 if _, ok := call.Args[0].(*influxql.VarRef); !ok { 872 return fmt.Errorf("expected first argument to be a field in %s(), found %s", call.Name, call.Args[0]) 873 } 874 875 if len(call.Args) > 2 { 876 for _, v := range call.Args[1 : len(call.Args)-1] { 877 ref, ok := v.(*influxql.VarRef) 878 if !ok { 879 return fmt.Errorf("only fields or tags are allowed in %s(), found %s", call.Name, v) 880 } 881 882 // Add a field for each of the listed dimensions when not writing the results. 883 if !c.global.HasTarget { 884 field := &compiledField{ 885 global: c.global, 886 Field: &influxql.Field{Expr: ref}, 887 } 888 c.global.Fields = append(c.global.Fields, field) 889 if err := field.compileExpr(ref); err != nil { 890 return err 891 } 892 } 893 } 894 } 895 c.global.TopBottomFunction = call.Name 896 return nil 897 } 898 899 func (c *compiledField) compileMathFunction(expr *influxql.Call) error { 900 // How many arguments are we expecting? 901 nargs := 1 902 switch expr.Name { 903 case "atan2", "pow", "log": 904 nargs = 2 905 } 906 907 // Did we get the expected number of args? 908 if got := len(expr.Args); got != nargs { 909 return fmt.Errorf("invalid number of arguments for %s, expected %d, got %d", expr.Name, nargs, got) 910 } 911 912 // Compile all the argument expressions that are not just literals. 913 for _, arg := range expr.Args { 914 if _, ok := arg.(influxql.Literal); ok { 915 continue 916 } 917 if err := c.compileExpr(arg); err != nil { 918 return err 919 } 920 } 921 return nil 922 } 923 924 func (c *compiledStatement) compileDimensions(stmt *influxql.SelectStatement) error { 925 for _, d := range stmt.Dimensions { 926 // Reduce the expression before attempting anything. Do not evaluate the call. 927 expr := influxql.Reduce(d.Expr, nil) 928 929 switch expr := expr.(type) { 930 case *influxql.VarRef: 931 if strings.EqualFold(expr.Val, "time") { 932 return errors.New("time() is a function and expects at least one argument") 933 } 934 case *influxql.Call: 935 // Ensure the call is time() and it has one or two duration arguments. 936 // If we already have a duration 937 if expr.Name != "time" { 938 return errors.New("only time() calls allowed in dimensions") 939 } else if got := len(expr.Args); got < 1 || got > 2 { 940 return errors.New("time dimension expected 1 or 2 arguments") 941 } else if lit, ok := expr.Args[0].(*influxql.DurationLiteral); !ok { 942 return errors.New("time dimension must have duration argument") 943 } else if c.Interval.Duration != 0 { 944 return errors.New("multiple time dimensions not allowed") 945 } else { 946 c.Interval.Duration = lit.Val 947 if len(expr.Args) == 2 { 948 switch lit := expr.Args[1].(type) { 949 case *influxql.DurationLiteral: 950 c.Interval.Offset = lit.Val % c.Interval.Duration 951 case *influxql.TimeLiteral: 952 c.Interval.Offset = lit.Val.Sub(lit.Val.Truncate(c.Interval.Duration)) 953 case *influxql.Call: 954 if lit.Name != "now" { 955 return errors.New("time dimension offset function must be now()") 956 } else if len(lit.Args) != 0 { 957 return errors.New("time dimension offset now() function requires no arguments") 958 } 959 now := c.Options.Now 960 c.Interval.Offset = now.Sub(now.Truncate(c.Interval.Duration)) 961 962 // Use the evaluated offset to replace the argument. Ideally, we would 963 // use the interval assigned above, but the query engine hasn't been changed 964 // to use the compiler information yet. 965 expr.Args[1] = &influxql.DurationLiteral{Val: c.Interval.Offset} 966 case *influxql.StringLiteral: 967 // If literal looks like a date time then parse it as a time literal. 968 if lit.IsTimeLiteral() { 969 t, err := lit.ToTimeLiteral(stmt.Location) 970 if err != nil { 971 return err 972 } 973 c.Interval.Offset = t.Val.Sub(t.Val.Truncate(c.Interval.Duration)) 974 } else { 975 return errors.New("time dimension offset must be duration or now()") 976 } 977 default: 978 return errors.New("time dimension offset must be duration or now()") 979 } 980 } 981 } 982 case *influxql.Wildcard: 983 case *influxql.RegexLiteral: 984 default: 985 return errors.New("only time and tag dimensions allowed") 986 } 987 988 // Assign the reduced/changed expression to the dimension. 989 d.Expr = expr 990 } 991 return nil 992 } 993 994 // validateFields validates that the fields are mutually compatible with each other. 995 // This runs at the end of compilation but before linking. 996 func (c *compiledStatement) validateFields() error { 997 // Validate that at least one field has been selected. 998 if len(c.Fields) == 0 { 999 return errors.New("at least 1 non-time field must be queried") 1000 } 1001 // Ensure there are not multiple calls if top/bottom is present. 1002 if len(c.FunctionCalls) > 1 && c.TopBottomFunction != "" { 1003 return fmt.Errorf("selector function %s() cannot be combined with other functions", c.TopBottomFunction) 1004 } else if len(c.FunctionCalls) == 0 { 1005 switch c.FillOption { 1006 case influxql.NoFill: 1007 return errors.New("fill(none) must be used with a function") 1008 case influxql.LinearFill: 1009 return errors.New("fill(linear) must be used with a function") 1010 } 1011 if !c.Interval.IsZero() && !c.InheritedInterval { 1012 return errors.New("GROUP BY requires at least one aggregate function") 1013 } 1014 } 1015 // If a distinct() call is present, ensure there is exactly one function. 1016 if c.HasDistinct && (len(c.FunctionCalls) != 1 || c.HasAuxiliaryFields) { 1017 return errors.New("aggregate function distinct() cannot be combined with other functions or fields") 1018 } 1019 // Validate we are using a selector or raw query if auxiliary fields are required. 1020 if c.HasAuxiliaryFields { 1021 if !c.OnlySelectors { 1022 return fmt.Errorf("mixing aggregate and non-aggregate queries is not supported") 1023 } else if len(c.FunctionCalls) > 1 { 1024 return fmt.Errorf("mixing multiple selector functions with tags or fields is not supported") 1025 } 1026 } 1027 return nil 1028 } 1029 1030 // validateCondition verifies that all elements in the condition are appropriate. 1031 // For example, aggregate calls don't work in the condition and should throw an 1032 // error as an invalid expression. 1033 func (c *compiledStatement) validateCondition(expr influxql.Expr) error { 1034 switch expr := expr.(type) { 1035 case *influxql.BinaryExpr: 1036 // Verify each side of the binary expression. We do not need to 1037 // verify the binary expression itself since that should have been 1038 // done by influxql.ConditionExpr. 1039 if err := c.validateCondition(expr.LHS); err != nil { 1040 return err 1041 } 1042 if err := c.validateCondition(expr.RHS); err != nil { 1043 return err 1044 } 1045 return nil 1046 case *influxql.Call: 1047 if !isMathFunction(expr) { 1048 return fmt.Errorf("invalid function call in condition: %s", expr) 1049 } 1050 1051 // How many arguments are we expecting? 1052 nargs := 1 1053 switch expr.Name { 1054 case "atan2", "pow": 1055 nargs = 2 1056 } 1057 1058 // Did we get the expected number of args? 1059 if got := len(expr.Args); got != nargs { 1060 return fmt.Errorf("invalid number of arguments for %s, expected %d, got %d", expr.Name, nargs, got) 1061 } 1062 1063 // Are all the args valid? 1064 for _, arg := range expr.Args { 1065 if err := c.validateCondition(arg); err != nil { 1066 return err 1067 } 1068 } 1069 return nil 1070 default: 1071 return nil 1072 } 1073 } 1074 1075 // subquery compiles and validates a compiled statement for the subquery using 1076 // this compiledStatement as the parent. 1077 func (c *compiledStatement) subquery(stmt *influxql.SelectStatement) error { 1078 subquery := newCompiler(c.Options) 1079 if err := subquery.preprocess(stmt); err != nil { 1080 return err 1081 } 1082 1083 // Substitute now() into the subquery condition. Then use ConditionExpr to 1084 // validate the expression. Do not store the results. We have no way to store 1085 // and read those results at the moment. 1086 valuer := influxql.MultiValuer( 1087 &influxql.NowValuer{Now: c.Options.Now, Location: stmt.Location}, 1088 &MathValuer{}, 1089 ) 1090 stmt.Condition = influxql.Reduce(stmt.Condition, valuer) 1091 1092 // If the ordering is different and the sort field was specified for the subquery, 1093 // throw an error. 1094 if len(stmt.SortFields) != 0 && subquery.Ascending != c.Ascending { 1095 return errors.New("subqueries must be ordered in the same direction as the query itself") 1096 } 1097 subquery.Ascending = c.Ascending 1098 1099 // Find the intersection between this time range and the parent. 1100 // If the subquery doesn't have a time range, this causes it to 1101 // inherit the parent's time range. 1102 subquery.TimeRange = subquery.TimeRange.Intersect(c.TimeRange) 1103 1104 // If the fill option is null, set it to none so we don't waste time on 1105 // null values with a redundant fill iterator. 1106 if !subquery.Interval.IsZero() && subquery.FillOption == influxql.NullFill { 1107 subquery.FillOption = influxql.NoFill 1108 } 1109 1110 // Inherit the grouping interval if the subquery has none. 1111 if !c.Interval.IsZero() && subquery.Interval.IsZero() { 1112 subquery.Interval = c.Interval 1113 subquery.InheritedInterval = true 1114 } 1115 return subquery.compile(stmt) 1116 } 1117 1118 func (c *compiledStatement) Prepare(ctx context.Context, shardMapper ShardMapper, sopt SelectOptions) (PreparedStatement, error) { 1119 // If this is a query with a grouping, there is a bucket limit, and the minimum time has not been specified, 1120 // we need to limit the possible time range that can be used when mapping shards but not when actually executing 1121 // the select statement. Determine the shard time range here. 1122 timeRange := c.TimeRange 1123 if sopt.MaxBucketsN > 0 && !c.stmt.IsRawQuery && timeRange.MinTimeNano() == influxql.MinTime { 1124 interval, err := c.stmt.GroupByInterval() 1125 if err != nil { 1126 return nil, err 1127 } 1128 1129 offset, err := c.stmt.GroupByOffset() 1130 if err != nil { 1131 return nil, err 1132 } 1133 1134 if interval > 0 { 1135 // Determine the last bucket using the end time. 1136 opt := IteratorOptions{ 1137 Interval: Interval{ 1138 Duration: interval, 1139 Offset: offset, 1140 }, 1141 } 1142 last, _ := opt.Window(c.TimeRange.MaxTimeNano() - 1) 1143 1144 // Determine the time difference using the number of buckets. 1145 // Determine the maximum difference between the buckets based on the end time. 1146 maxDiff := last - models.MinNanoTime 1147 if maxDiff/int64(interval) > int64(sopt.MaxBucketsN) { 1148 timeRange.Min = time.Unix(0, models.MinNanoTime) 1149 } else { 1150 timeRange.Min = time.Unix(0, last-int64(interval)*int64(sopt.MaxBucketsN-1)) 1151 } 1152 } 1153 } 1154 1155 // Modify the time range if there are extra intervals and an interval. 1156 if !c.Interval.IsZero() && c.ExtraIntervals > 0 { 1157 if c.Ascending { 1158 newTime := timeRange.Min.Add(time.Duration(-c.ExtraIntervals) * c.Interval.Duration) 1159 if !newTime.Before(time.Unix(0, influxql.MinTime).UTC()) { 1160 timeRange.Min = newTime 1161 } else { 1162 timeRange.Min = time.Unix(0, influxql.MinTime).UTC() 1163 } 1164 } else { 1165 newTime := timeRange.Max.Add(time.Duration(c.ExtraIntervals) * c.Interval.Duration) 1166 if !newTime.After(time.Unix(0, influxql.MaxTime).UTC()) { 1167 timeRange.Max = newTime 1168 } else { 1169 timeRange.Max = time.Unix(0, influxql.MaxTime).UTC() 1170 } 1171 } 1172 } 1173 1174 // Create an iterator creator based on the shards in the cluster. 1175 shards, err := shardMapper.MapShards(ctx, c.stmt.Sources, timeRange, sopt) 1176 if err != nil { 1177 return nil, err 1178 } 1179 1180 // Rewrite wildcards, if any exist. 1181 mapper := queryFieldMapper{FieldMapper: newFieldMapperAdapter(shards, ctx)} 1182 stmt, err := c.stmt.RewriteFields(mapper) 1183 if err != nil { 1184 shards.Close() 1185 return nil, err 1186 } 1187 1188 // Validate if the types are correct now that they have been assigned. 1189 if err := validateTypes(stmt); err != nil { 1190 shards.Close() 1191 return nil, err 1192 } 1193 1194 // Determine base options for iterators. 1195 opt, err := newIteratorOptionsStmt(stmt, sopt) 1196 if err != nil { 1197 shards.Close() 1198 return nil, err 1199 } 1200 opt.StartTime, opt.EndTime = c.TimeRange.MinTimeNano(), c.TimeRange.MaxTimeNano() 1201 opt.Ascending = c.Ascending 1202 1203 if sopt.MaxBucketsN > 0 && !stmt.IsRawQuery && c.TimeRange.MinTimeNano() > influxql.MinTime { 1204 interval, err := stmt.GroupByInterval() 1205 if err != nil { 1206 shards.Close() 1207 return nil, err 1208 } 1209 1210 if interval > 0 { 1211 // Determine the start and end time matched to the interval (may not match the actual times). 1212 first, _ := opt.Window(opt.StartTime) 1213 last, _ := opt.Window(opt.EndTime - 1) 1214 1215 // Determine the number of buckets by finding the time span and dividing by the interval. 1216 buckets := (last - first + int64(interval)) / int64(interval) 1217 if int(buckets) > sopt.MaxBucketsN { 1218 shards.Close() 1219 return nil, fmt.Errorf("max-select-buckets limit exceeded: (%d/%d)", buckets, sopt.MaxBucketsN) 1220 } 1221 } 1222 } 1223 1224 columns := stmt.ColumnNames() 1225 return &preparedStatement{ 1226 stmt: stmt, 1227 opt: opt, 1228 ic: shards, 1229 columns: columns, 1230 maxPointN: sopt.MaxPointN, 1231 now: c.Options.Now, 1232 }, nil 1233 }