/vendor/github.com/influxdata/influxdb/services/storage/predicate_influxql.go

https://bitbucket.org/egym-com/dns-tools · Go · 262 lines · 209 code · 49 blank · 4 comment · 47 complexity · d5b5fce5d1fd791771be7705d12f0550 MD5 · raw file

  1. package storage
  2. import (
  3. "errors"
  4. "regexp"
  5. "github.com/influxdata/influxql"
  6. )
  7. // NodeToExpr transforms a predicate node to an influxql.Expr.
  8. func NodeToExpr(node *Node) (influxql.Expr, error) {
  9. var v nodeToExprVisitor
  10. WalkNode(&v, node)
  11. if err := v.Err(); err != nil {
  12. return nil, err
  13. }
  14. if len(v.exprs) > 1 {
  15. return nil, errors.New("invalid expression")
  16. }
  17. if len(v.exprs) == 0 {
  18. return nil, nil
  19. }
  20. return v.exprs[0], nil
  21. }
  22. type nodeToExprVisitor struct {
  23. exprs []influxql.Expr
  24. err error
  25. }
  26. func (v *nodeToExprVisitor) Visit(n *Node) NodeVisitor {
  27. if v.err != nil {
  28. return nil
  29. }
  30. switch n.NodeType {
  31. case NodeTypeLogicalExpression:
  32. if len(n.Children) > 1 {
  33. op := influxql.AND
  34. if n.GetLogical() == LogicalOr {
  35. op = influxql.OR
  36. }
  37. WalkNode(v, n.Children[0])
  38. if v.err != nil {
  39. return nil
  40. }
  41. for i := 1; i < len(n.Children); i++ {
  42. WalkNode(v, n.Children[i])
  43. if v.err != nil {
  44. return nil
  45. }
  46. if len(v.exprs) >= 2 {
  47. lhs, rhs := v.pop2()
  48. v.exprs = append(v.exprs, &influxql.BinaryExpr{LHS: lhs, Op: op, RHS: rhs})
  49. }
  50. }
  51. return nil
  52. }
  53. case NodeTypeParenExpression:
  54. if len(n.Children) != 1 {
  55. v.err = errors.New("ParenExpression expects one child")
  56. return nil
  57. }
  58. WalkNode(v, n.Children[0])
  59. if v.err != nil {
  60. return nil
  61. }
  62. if len(v.exprs) > 0 {
  63. v.exprs = append(v.exprs, &influxql.ParenExpr{Expr: v.pop()})
  64. }
  65. return nil
  66. case NodeTypeComparisonExpression:
  67. walkChildren(v, n)
  68. if len(v.exprs) < 2 {
  69. v.err = errors.New("ComparisonExpression expects two children")
  70. return nil
  71. }
  72. lhs, rhs := v.pop2()
  73. be := &influxql.BinaryExpr{LHS: lhs, RHS: rhs}
  74. switch n.GetComparison() {
  75. case ComparisonEqual:
  76. be.Op = influxql.EQ
  77. case ComparisonNotEqual:
  78. be.Op = influxql.NEQ
  79. case ComparisonStartsWith:
  80. // TODO(sgc): rewrite to anchored RE, as index does not support startsWith yet
  81. v.err = errors.New("startsWith not implemented")
  82. return nil
  83. case ComparisonRegex:
  84. be.Op = influxql.EQREGEX
  85. case ComparisonNotRegex:
  86. be.Op = influxql.NEQREGEX
  87. case ComparisonLess:
  88. be.Op = influxql.LT
  89. case ComparisonLessEqual:
  90. be.Op = influxql.LTE
  91. case ComparisonGreater:
  92. be.Op = influxql.GT
  93. case ComparisonGreaterEqual:
  94. be.Op = influxql.GTE
  95. default:
  96. v.err = errors.New("invalid comparison operator")
  97. return nil
  98. }
  99. v.exprs = append(v.exprs, be)
  100. return nil
  101. case NodeTypeTagRef:
  102. ref := n.GetTagRefValue()
  103. if ref == "_measurement" {
  104. // as tsdb.Index expects _name for measurement name
  105. ref = "_name"
  106. }
  107. v.exprs = append(v.exprs, &influxql.VarRef{Val: ref})
  108. return nil
  109. case NodeTypeFieldRef:
  110. v.exprs = append(v.exprs, &influxql.VarRef{Val: "$"})
  111. return nil
  112. case NodeTypeLiteral:
  113. switch val := n.Value.(type) {
  114. case *Node_StringValue:
  115. v.exprs = append(v.exprs, &influxql.StringLiteral{Val: val.StringValue})
  116. case *Node_RegexValue:
  117. // TODO(sgc): consider hashing the RegexValue and cache compiled version
  118. re, err := regexp.Compile(val.RegexValue)
  119. if err != nil {
  120. v.err = err
  121. }
  122. v.exprs = append(v.exprs, &influxql.RegexLiteral{Val: re})
  123. return nil
  124. case *Node_IntegerValue:
  125. v.exprs = append(v.exprs, &influxql.IntegerLiteral{Val: val.IntegerValue})
  126. case *Node_UnsignedValue:
  127. v.exprs = append(v.exprs, &influxql.UnsignedLiteral{Val: val.UnsignedValue})
  128. case *Node_FloatValue:
  129. v.exprs = append(v.exprs, &influxql.NumberLiteral{Val: val.FloatValue})
  130. case *Node_BooleanValue:
  131. v.exprs = append(v.exprs, &influxql.BooleanLiteral{Val: val.BooleanValue})
  132. default:
  133. v.err = errors.New("unexpected literal type")
  134. return nil
  135. }
  136. return nil
  137. default:
  138. return v
  139. }
  140. return nil
  141. }
  142. func (v *nodeToExprVisitor) Err() error {
  143. return v.err
  144. }
  145. func (v *nodeToExprVisitor) pop() influxql.Expr {
  146. if len(v.exprs) == 0 {
  147. panic("stack empty")
  148. }
  149. var top influxql.Expr
  150. top, v.exprs = v.exprs[len(v.exprs)-1], v.exprs[:len(v.exprs)-1]
  151. return top
  152. }
  153. func (v *nodeToExprVisitor) pop2() (influxql.Expr, influxql.Expr) {
  154. if len(v.exprs) < 2 {
  155. panic("stack empty")
  156. }
  157. rhs := v.exprs[len(v.exprs)-1]
  158. lhs := v.exprs[len(v.exprs)-2]
  159. v.exprs = v.exprs[:len(v.exprs)-2]
  160. return lhs, rhs
  161. }
  162. type hasRefs struct {
  163. refs []string
  164. found bool
  165. }
  166. func (v *hasRefs) Visit(node influxql.Node) influxql.Visitor {
  167. if v.found {
  168. return nil
  169. }
  170. if n, ok := node.(*influxql.VarRef); ok {
  171. for _, r := range v.refs {
  172. if r == n.Val {
  173. v.found = true
  174. return nil
  175. }
  176. }
  177. }
  178. return v
  179. }
  180. func HasFieldKey(expr influxql.Expr) bool {
  181. refs := hasRefs{refs: []string{"_field"}}
  182. influxql.Walk(&refs, expr)
  183. return refs.found
  184. }
  185. func HasFieldKeyOrValue(expr influxql.Expr) bool {
  186. refs := hasRefs{refs: []string{"_field", "$"}}
  187. influxql.Walk(&refs, expr)
  188. return refs.found
  189. }
  190. func RewriteExprRemoveFieldKeyAndValue(expr influxql.Expr) influxql.Expr {
  191. return influxql.RewriteExpr(expr, func(expr influxql.Expr) influxql.Expr {
  192. if be, ok := expr.(*influxql.BinaryExpr); ok {
  193. if ref, ok := be.LHS.(*influxql.VarRef); ok {
  194. if ref.Val == "_field" || ref.Val == "$" {
  195. return &influxql.BooleanLiteral{Val: true}
  196. }
  197. }
  198. }
  199. return expr
  200. })
  201. }
  202. func RewriteExprRemoveFieldValue(expr influxql.Expr) influxql.Expr {
  203. return influxql.RewriteExpr(expr, func(expr influxql.Expr) influxql.Expr {
  204. if be, ok := expr.(*influxql.BinaryExpr); ok {
  205. if ref, ok := be.LHS.(*influxql.VarRef); ok {
  206. if ref.Val == "$" {
  207. return &influxql.BooleanLiteral{Val: true}
  208. }
  209. }
  210. }
  211. return expr
  212. })
  213. }