promql.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. package translator
  2. import (
  3. "fmt"
  4. "log"
  5. "strconv"
  6. "strings"
  7. "time"
  8. "github.com/influxdata/influxql"
  9. "github.com/influxdata/promql/v2"
  10. "github.com/influxdata/promql/v2/pkg/labels"
  11. "github.com/pkg/errors"
  12. "github.com/prometheus/common/model"
  13. )
  14. const UNION_RESULT_NAME = "__union_result__"
  15. const (
  16. CALL_TOP = "top"
  17. CALL_BOTTOM = "bottom"
  18. CALL_PERCENTILE = "percentile"
  19. CALL_SUM = "sum"
  20. CALL_MIN = "min"
  21. CALL_MAX = "max"
  22. )
  23. var MUL_ARGS_AGGREGATOR MulArgsAggregator = []string{CALL_TOP, CALL_PERCENTILE, CALL_BOTTOM}
  24. type MulArgsAggregator []string
  25. func (m MulArgsAggregator) Has(aggr string) bool {
  26. for _, a := range m {
  27. if a == aggr {
  28. return true
  29. }
  30. }
  31. return false
  32. }
  33. type promQL struct {
  34. groupByWildcard bool
  35. timeRange *influxql.TimeRange
  36. fieldIsWildcard bool
  37. measurement string
  38. labelsVisitor *labelsVisitor
  39. }
  40. func NewPromQL() Translator {
  41. return &promQL{
  42. labelsVisitor: newLabelsVisitor(),
  43. }
  44. }
  45. func (m *promQL) Translate(s influxql.Statement) (string, error) {
  46. selectS, ok := s.(*influxql.SelectStatement)
  47. if !ok {
  48. return "", errors.Errorf("Only SelectStatement is supported, input %t", s)
  49. }
  50. return m.translate(selectS)
  51. }
  52. func (m *promQL) GetTimeRange() *influxql.TimeRange {
  53. return m.timeRange
  54. }
  55. type fieldResult struct {
  56. metricName string
  57. aggrOps []*AggrOperator
  58. expr promql.Expr
  59. }
  60. func newFieldResult(metricName string, ops []*AggrOperator, expr promql.Expr) *fieldResult {
  61. return &fieldResult{
  62. metricName: metricName,
  63. aggrOps: ops,
  64. expr: expr,
  65. }
  66. }
  67. func (m *promQL) translateField(s *influxql.SelectStatement, field *influxql.Field) (*fieldResult, error) {
  68. metricName, err := getMetricName(s.Sources, field)
  69. if err != nil {
  70. if errors.Cause(err) == ErrVariableIsWildcard {
  71. m.measurement = metricName
  72. m.fieldIsWildcard = true
  73. } else {
  74. return nil, errors.Wrap(err, "getMetricName")
  75. }
  76. }
  77. aggrOps, err := getAggrOperators(field)
  78. if err != nil {
  79. return nil, errors.Wrap(err, "get field aggregate operator")
  80. }
  81. cond, timeRange, err := getTimeRange(s.Condition)
  82. if err != nil {
  83. return nil, errors.Wrap(err, "getTimeRange")
  84. }
  85. m.timeRange = timeRange
  86. matchers, err := m.getLabels(m.labelsVisitor, cond)
  87. if err != nil {
  88. return nil, errors.Wrap(err, "get matchers")
  89. }
  90. if !m.fieldIsWildcard {
  91. nameMatcher, _ := labels.NewMatcher(labels.MatchEqual, labels.MetricName, metricName)
  92. matchers = append(matchers, nameMatcher)
  93. }
  94. lookbehindWin, groups, err := m.getGroups(s.Dimensions)
  95. if err != nil {
  96. return nil, errors.Wrap(err, "get groups")
  97. }
  98. //interval, err := s.GroupByInterval()
  99. //if err != nil {
  100. // return "", errors.Wrap(err, "GroupByInterval")
  101. //}
  102. //fmt.Printf("==get interval: %#v\n", interval)
  103. expr, err := m.generateExpr(metricName, matchers, lookbehindWin, aggrOps, groups)
  104. if err != nil {
  105. return nil, errors.Wrap(err, "generate expression")
  106. }
  107. return newFieldResult(metricName, aggrOps, expr), nil
  108. }
  109. func (m *promQL) translate(s *influxql.SelectStatement) (string, error) {
  110. exprs := make([]*fieldResult, 0)
  111. var resultExpr promql.Expr
  112. for _, field := range s.Fields {
  113. expr, err := m.translateField(s, field)
  114. if err != nil {
  115. return "", errors.Wrapf(err, "translate field %s", field)
  116. }
  117. exprs = append(exprs, expr)
  118. }
  119. if len(exprs) == 1 {
  120. resultExpr = exprs[0].expr
  121. } else {
  122. // union field expr
  123. resultExpr = unionFieldsExpr(exprs)
  124. }
  125. return m.formatExpr(resultExpr), nil
  126. }
  127. func unionFieldsExpr(exprs []*fieldResult) promql.Expr {
  128. result := make([]promql.Expr, len(exprs))
  129. // 1. wrap each expr with label_set: https://docs.victoriametrics.com/MetricsQL.html#label_set
  130. setKey := UNION_RESULT_NAME
  131. for i := range exprs {
  132. expr := exprs[i]
  133. setValue := expr.metricName
  134. if len(expr.aggrOps) > 0 {
  135. opsNames := make([]string, len(expr.aggrOps))
  136. for i := range expr.aggrOps {
  137. opsNames[i] = expr.aggrOps[i].Name
  138. }
  139. setValue = fmt.Sprintf("%s_%s", strings.Join(opsNames, "_"), expr.metricName)
  140. }
  141. result[i] = &promql.Call{
  142. Func: &promql.Function{
  143. Name: "label_set",
  144. ArgTypes: []promql.ValueType{promql.ValueTypeVector, promql.ValueTypeString, promql.ValueTypeString},
  145. Variadic: 1,
  146. ReturnType: promql.ValueTypeVector,
  147. },
  148. Args: promql.Expressions{
  149. expr.expr,
  150. &promql.StringLiteral{setKey},
  151. &promql.StringLiteral{setValue},
  152. },
  153. }
  154. }
  155. // 2. use union: https://docs.victoriametrics.com/MetricsQL.html#union
  156. return &promql.Call{
  157. Func: &promql.Function{
  158. Name: "union",
  159. Variadic: 1,
  160. ReturnType: promql.ValueTypeVector,
  161. },
  162. Args: result,
  163. }
  164. }
  165. func getTimeRange(cond influxql.Expr) (influxql.Expr, *influxql.TimeRange, error) {
  166. // parse time range
  167. //mustParseTime := func(value string) time.Time {
  168. // ts, err := time.Parse(time.RFC3339, value)
  169. // if err != nil {
  170. // panic(fmt.Errorf("unable to parse time: %s", err))
  171. // }
  172. // return ts
  173. //}
  174. //now := mustParseTime("2000-01-01T00:00:00Z")
  175. valuer := influxql.NowValuer{
  176. Now: time.Now(),
  177. Location: time.UTC,
  178. }
  179. cond, timeRange, err := influxql.ConditionExpr(cond, &valuer)
  180. if err != nil {
  181. return nil, nil, errors.Wrapf(err, "parse time range from %q", cond)
  182. }
  183. if timeRange.IsZero() {
  184. return cond, nil, nil
  185. }
  186. // process maxTime
  187. if !timeRange.MaxTime().IsZero() {
  188. year, month, day := timeRange.Max.Date()
  189. // FIX: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)
  190. if year == 1 && month == 1 && day == 1 {
  191. timeRange.Max = time.Now()
  192. }
  193. }
  194. return cond, &timeRange, nil
  195. }
  196. func (m promQL) generateExpr(
  197. metricName string,
  198. ls []*labels.Matcher,
  199. lookbehindWindow string,
  200. aggrOps []*AggrOperator,
  201. groups []string) (promql.Expr, error) {
  202. //fmt.Printf("=====name: %s, labels: %#v, lookbehindWindow: %q, aggrOps: %#v, groups: %#v\n", metricName, ls, lookbehindWindow, aggrOps, groups)
  203. for _, l := range ls {
  204. fmt.Printf("label: %s\n", l.String())
  205. }
  206. if m.fieldIsWildcard {
  207. measurementM, _ := labels.NewMatcher(labels.MatchRegexp, labels.MetricName, fmt.Sprintf("^%s_.*", m.measurement))
  208. ls = append(ls, measurementM)
  209. }
  210. var result promql.Expr
  211. if len(aggrOps) != 0 {
  212. if lookbehindWindow == "" {
  213. lookbehindWindow = "1m"
  214. }
  215. dur, err := model.ParseDuration(lookbehindWindow)
  216. if err != nil {
  217. return nil, errors.Wrapf(err, "ParseDuration: %q", lookbehindWindow)
  218. }
  219. ms := &promql.MatrixSelector{
  220. LabelMatchers: ls,
  221. Range: time.Duration(dur),
  222. }
  223. if !m.fieldIsWildcard {
  224. ms.Name = metricName
  225. }
  226. result = ms
  227. } else {
  228. vs := &promql.VectorSelector{
  229. LabelMatchers: ls,
  230. }
  231. if !m.fieldIsWildcard {
  232. vs.Name = metricName
  233. }
  234. result = vs
  235. }
  236. if len(groups) != 0 && len(aggrOps) == 0 {
  237. return nil, errors.Errorf("Can't use group by when aggregate operator is empty")
  238. }
  239. result = getAggrExpr(aggrOps, result)
  240. //fmt.Printf("=====m.GroupByWildcard: %v, %#v, aggrOps: %#v\n", m.groupByWildcard, result, aggrOps)
  241. shouldSkipAggr := func(opName string) bool {
  242. switch opName {
  243. case CALL_PERCENTILE, CALL_TOP, CALL_BOTTOM, "last":
  244. return true
  245. }
  246. return false
  247. }
  248. if len(aggrOps) != 0 {
  249. op := promql.ItemAvg
  250. opName := aggrOps[0].Name
  251. if !shouldSkipAggr(opName) {
  252. switch opName {
  253. case CALL_SUM:
  254. op = promql.ItemSum
  255. case CALL_MAX:
  256. op = promql.ItemMax
  257. case CALL_MIN:
  258. op = promql.ItemMin
  259. }
  260. expr := &promql.AggregateExpr{
  261. Op: op,
  262. Expr: result,
  263. }
  264. if len(groups) != 0 {
  265. expr.Grouping = groups
  266. }
  267. if !m.groupByWildcard {
  268. result = expr
  269. }
  270. }
  271. }
  272. return result, nil
  273. }
  274. func (m promQL) formatExpr(expr promql.Expr) string {
  275. initialExpr := expr.String()
  276. //fmt.Printf("---replaceLabels: %#v\n", m.labelsVisitor.replaceLabels)
  277. //fmt.Printf("--src: %s\n", initialExpr)
  278. if len(m.labelsVisitor.replaceLabels) > 0 && len(m.labelsVisitor.labels) > 1 {
  279. for src, replace := range m.labelsVisitor.replaceLabels {
  280. initialExpr = strings.ReplaceAll(initialExpr, src, replace)
  281. }
  282. }
  283. return initialExpr
  284. }
  285. func newAggrExpr(name string, argType promql.ValueType, returnType promql.ValueType, restExpr promql.Expr) promql.Expr {
  286. return newAggrExprWithArgs(name, []promql.ValueType{argType}, returnType, promql.Expressions{restExpr})
  287. }
  288. func newAggrExprWithArgs(name string, args []promql.ValueType, returnType promql.ValueType, restExprs promql.Expressions) promql.Expr {
  289. return &promql.Call{
  290. Func: &promql.Function{
  291. Name: name,
  292. ArgTypes: args,
  293. Variadic: 0,
  294. ReturnType: returnType,
  295. },
  296. Args: restExprs,
  297. }
  298. }
  299. func getAggrExpr(ops []*AggrOperator, expr promql.Expr) promql.Expr {
  300. if len(ops) == 0 {
  301. return expr
  302. }
  303. aggrOp := ops[0]
  304. restOps := ops[1:]
  305. restExpr := getAggrExpr(restOps, expr)
  306. switch aggrOp.Name {
  307. case "abs":
  308. // https://prometheus.io/docs/prometheus/latest/querying/functions/#abs
  309. expr = newAggrExpr("abs", promql.ValueTypeVector, promql.ValueTypeVector, restExpr)
  310. case "mean":
  311. // https://docs.victoriametrics.com/MetricsQL.html#avg_over_time
  312. expr = newAggrExpr("avg_over_time", promql.ValueTypeMatrix, promql.ValueTypeVector, restExpr)
  313. case "last":
  314. // https://docs.victoriametrics.com/MetricsQL.html#last_over_time
  315. expr = newAggrExpr("last_over_time", promql.ValueTypeMatrix, promql.ValueTypeVector, restExpr)
  316. case "stddev":
  317. // https://prometheus.io/docs/prometheus/latest/querying/functions/#aggregation_over_time
  318. expr = newAggrExpr("stddev_over_time", promql.ValueTypeMatrix, promql.ValueTypeVector, restExpr)
  319. case "count":
  320. // use count, not use 'count_over_time' https://docs.victoriametrics.com/MetricsQL.html#count_over_time
  321. expr = newAggrExpr("count", promql.ValueTypeMatrix, promql.ValueTypeVector, restExpr)
  322. case "median":
  323. // https://docs.victoriametrics.com/MetricsQL.html#median_over_time
  324. expr = newAggrExpr("median_over_time", promql.ValueTypeMatrix, promql.ValueTypeVector, restExpr)
  325. /*case "max":
  326. // https://docs.victoriametrics.com/MetricsQL.html#max_over_time
  327. expr = newAggrExpr("max", promql.ValueTypeMatrix, promql.ValueTypeVector, restExpr)
  328. case "min":
  329. // https://docs.victoriametrics.com/MetricsQL.html#min_over_time
  330. expr = newAggrExpr("min", promql.ValueTypeMatrix, promql.ValueTypeVector, restExpr)*/
  331. case "mode":
  332. // https://docs.victoriametrics.com/MetricsQL.html#mode_over_time
  333. expr = newAggrExpr("mode_over_time", promql.ValueTypeMatrix, promql.ValueTypeVector, restExpr)
  334. case "integral":
  335. // https://docs.victoriametrics.com/MetricsQL.html#integrate
  336. expr = newAggrExpr("integrate", promql.ValueTypeMatrix, promql.ValueTypeVector, restExpr)
  337. case "distinct":
  338. expr = newAggrExpr("distinct", promql.ValueTypeMatrix, promql.ValueTypeVector, restExpr)
  339. case CALL_TOP:
  340. expr = newAggrExprWithArgs("topk_avg",
  341. []promql.ValueType{
  342. promql.ValueTypeString,
  343. promql.ValueTypeMatrix,
  344. }, promql.ValueTypeVector,
  345. promql.Expressions{
  346. aggrOp.Args[0],
  347. restExpr})
  348. case CALL_BOTTOM:
  349. expr = newAggrExprWithArgs("bottomk_avg",
  350. []promql.ValueType{
  351. promql.ValueTypeString,
  352. promql.ValueTypeMatrix,
  353. }, promql.ValueTypeVector,
  354. promql.Expressions{
  355. aggrOp.Args[0],
  356. restExpr})
  357. case CALL_PERCENTILE:
  358. expr = newAggrExprWithArgs("quantile_over_time",
  359. []promql.ValueType{
  360. promql.ValueTypeString,
  361. promql.ValueTypeMatrix,
  362. }, promql.ValueTypeVector,
  363. promql.Expressions{
  364. aggrOp.Args[0],
  365. restExpr})
  366. }
  367. return expr
  368. }
  369. type AggrOperator struct {
  370. Name string
  371. Args promql.Expressions
  372. }
  373. func newAggrOperatorByName(name string) *AggrOperator {
  374. return &AggrOperator{
  375. Name: name,
  376. }
  377. }
  378. func getAggrOperator(op *influxql.Call) ([]*AggrOperator, error) {
  379. if len(op.Args) != 1 && !MUL_ARGS_AGGREGATOR.Has(op.Name) {
  380. return nil, errors.Errorf("not supported aggregator: %s with args: %#v", op.String(), op.Args)
  381. }
  382. aggOp := newAggrOperatorByName(op.Name)
  383. if op.Name == CALL_TOP || op.Name == CALL_BOTTOM || op.Name == CALL_PERCENTILE {
  384. numStr := op.Args[len(op.Args)-1].String()
  385. num, err := strconv.Atoi(numStr)
  386. if err != nil {
  387. return nil, errors.Wrapf(err, "parse top/bottom aggregator: %s", op)
  388. }
  389. numFloat := float64(num)
  390. if op.Name == CALL_PERCENTILE {
  391. if numFloat > 100 {
  392. return nil, errors.Errorf("percentile %f is large than 100", numFloat)
  393. }
  394. numFloat = numFloat / 100
  395. }
  396. aggOp.Args = promql.Expressions{
  397. &promql.NumberLiteral{Val: numFloat},
  398. }
  399. }
  400. ret := []*AggrOperator{aggOp}
  401. args, ok := op.Args[0].(*influxql.Call)
  402. if !ok {
  403. return ret, nil
  404. }
  405. rest, err := getAggrOperator(args)
  406. if err != nil {
  407. return nil, errors.Wrapf(err, "get rest aggregate operator: %s", args.String())
  408. }
  409. ret = append(ret, rest...)
  410. return ret, nil
  411. }
  412. func getAggrOperators(field *influxql.Field) ([]*AggrOperator, error) {
  413. aggrOp, ok := field.Expr.(*influxql.Call)
  414. if !ok {
  415. return nil, nil
  416. }
  417. return getAggrOperator(aggrOp)
  418. }
  419. func getMetricName(sources influxql.Sources, field *influxql.Field) (string, error) {
  420. if len(sources) != 1 {
  421. return "", errors.Errorf("sources %#v length doesn't equal 1", sources)
  422. }
  423. src := sources[0]
  424. measurement, ok := src.(*influxql.Measurement)
  425. if !ok {
  426. return "", errors.Errorf("source %#v is not measurement type", src)
  427. }
  428. var (
  429. fieldName string
  430. err error
  431. )
  432. switch expr := field.Expr.(type) {
  433. case *influxql.VarRef:
  434. fieldName = expr.Val
  435. case *influxql.Call:
  436. fieldName, err = getCallVariable(expr)
  437. default:
  438. return "", errors.Errorf("field.Expr %#v is not supported", expr)
  439. }
  440. if err != nil {
  441. return measurement.Name, err
  442. }
  443. return fmt.Sprintf("%s_%s", measurement.Name, fieldName), nil
  444. }
  445. var (
  446. ErrVariableIsWildcard = errors.New("variable field is wildcard")
  447. )
  448. func getCallVariable(c *influxql.Call) (string, error) {
  449. if len(c.Args) != 1 && !MUL_ARGS_AGGREGATOR.Has(c.Name) {
  450. return "", errors.Errorf("length of call %q args %#v != 1", c.Name, c.Args)
  451. }
  452. switch args := c.Args[0].(type) {
  453. case *influxql.VarRef:
  454. return args.Val, nil
  455. case *influxql.Wildcard:
  456. return "", ErrVariableIsWildcard
  457. case *influxql.Call:
  458. return getCallVariable(args)
  459. default:
  460. return "", errors.Errorf("unsupported args %#v", args)
  461. }
  462. return c.Args[0].String(), nil
  463. }
  464. type labelsVisitor struct {
  465. err error
  466. labels []*labels.Matcher
  467. curKey string
  468. curOp influxql.Token
  469. curVal string
  470. replaceLabels map[string]string
  471. }
  472. func newLabelsVisitor() *labelsVisitor {
  473. return &labelsVisitor{
  474. err: nil,
  475. labels: make([]*labels.Matcher, 0),
  476. replaceLabels: map[string]string{},
  477. }
  478. }
  479. func (l *labelsVisitor) Error() error {
  480. return l.err
  481. }
  482. func (l *labelsVisitor) Labels() []*labels.Matcher {
  483. return l.labels
  484. }
  485. func (l *labelsVisitor) commitLabel() error {
  486. if l.err != nil {
  487. return l.err
  488. }
  489. var (
  490. label *labels.Matcher
  491. err error
  492. )
  493. var promOP labels.MatchType
  494. switch l.curOp {
  495. case influxql.EQ:
  496. promOP = labels.MatchEqual
  497. case influxql.NEQ:
  498. promOP = labels.MatchNotEqual
  499. case influxql.EQREGEX:
  500. promOP = labels.MatchRegexp
  501. case influxql.NEQREGEX:
  502. promOP = labels.MatchNotRegexp
  503. default:
  504. return errors.Errorf("Not suport influxdb operator: %s", l.curOp)
  505. }
  506. label, err = labels.NewMatcher(promOP, l.curKey, l.curVal)
  507. if err != nil {
  508. return errors.Wrapf(err, "not supported operator: %q", l.curOp)
  509. }
  510. l.labels = append(l.labels, label)
  511. return nil
  512. }
  513. func (l *labelsVisitor) Visit(node influxql.Node) influxql.Visitor {
  514. //fmt.Printf("-- visit: %s, %#v\n", node, node)
  515. if l.err != nil {
  516. log.Printf("error happend: %v, visting skipped", l.err)
  517. return l
  518. }
  519. switch expr := node.(type) {
  520. case *influxql.BinaryExpr:
  521. if expr.Op != influxql.OR && expr.Op != influxql.AND {
  522. l.curOp = expr.Op
  523. }
  524. l.Visit(expr.LHS)
  525. if expr.Op == influxql.OR {
  526. curLabel := l.labels[len(l.labels)-1]
  527. key := fmt.Sprintf("%s,", curLabel.String())
  528. l.replaceLabels[key] = fmt.Sprintf("%s or ", curLabel.String())
  529. }
  530. l.Visit(expr.RHS)
  531. return nil
  532. case *influxql.VarRef:
  533. l.curKey = expr.Val
  534. case *influxql.StringLiteral:
  535. l.curVal = expr.Val
  536. if err := l.commitLabel(); err != nil {
  537. l.err = err
  538. }
  539. case *influxql.RegexLiteral:
  540. l.curVal = expr.Val.String()
  541. if err := l.commitLabel(); err != nil {
  542. l.err = err
  543. }
  544. }
  545. return l
  546. }
  547. func (m promQL) getLabels(v *labelsVisitor, cond influxql.Expr) ([]*labels.Matcher, error) {
  548. if cond == nil {
  549. return nil, nil
  550. }
  551. influxql.Walk(v, cond)
  552. return v.Labels(), v.Error()
  553. }
  554. func (m *promQL) getGroups(groups influxql.Dimensions) (string, []string, error) {
  555. result := []string{}
  556. var (
  557. lookbehindWindow string
  558. )
  559. for _, group := range groups {
  560. tmpWin, grp, err := m.getGroup(group)
  561. if err != nil {
  562. return "", result, errors.Wrapf(err, "getGroup %q", group)
  563. }
  564. if tmpWin != "" {
  565. lookbehindWindow = tmpWin
  566. }
  567. if grp != "" {
  568. result = append(result, grp)
  569. }
  570. }
  571. return lookbehindWindow, result, nil
  572. }
  573. func (m *promQL) getGroup(group *influxql.Dimension) (string, string, error) {
  574. //fmt.Printf("---try group: %#v\n", group)
  575. grp := group.Expr
  576. lookbehindWindow := ""
  577. switch expr := grp.(type) {
  578. case *influxql.Call:
  579. if expr.Name == "time" {
  580. lookbehindWindow = expr.Args[0].String()
  581. }
  582. return lookbehindWindow, "", nil
  583. case *influxql.VarRef:
  584. return "", expr.Val, nil
  585. case *influxql.Wildcard:
  586. m.groupByWildcard = true
  587. return "", "", nil
  588. }
  589. return "", "", errors.Errorf("not support %q", group.String())
  590. }