buildRangePruner creates a DAG comparison expression that can evalaute whether a value adhering to the from/to pattern can be excluded from a scan because the expression pred would evaluate to false for all values of fld in the from/to value range. If a pruning decision cannot be reliably determine
(pred dag.Expr, fld field.Path, min, max *dag.ThisExpr)
| 40 | // from/to value range. If a pruning decision cannot be reliably determined then |
| 41 | // the return value is nil. |
| 42 | func buildRangePruner(pred dag.Expr, fld field.Path, min, max *dag.ThisExpr) *dag.BinaryExpr { |
| 43 | e, ok := pred.(*dag.BinaryExpr) |
| 44 | if !ok { |
| 45 | // If this isn't a binary predicate composed of comparison operators, we |
| 46 | // simply punt here. This doesn't mean we can't optimize, because if the |
| 47 | // unknown part (from here) appears in the context of an "and", then we |
| 48 | // can still prune the known side of the "and" as implemented in the |
| 49 | // logic below. |
| 50 | return nil |
| 51 | } |
| 52 | switch e.Op { |
| 53 | case "and": |
| 54 | // For an "and", if we know either side is prunable, then we can prune |
| 55 | // because both conditions are required. So we "or" together the result |
| 56 | // when both sub-expressions are valid. |
| 57 | lhs := buildRangePruner(e.LHS, fld, min, max) |
| 58 | rhs := buildRangePruner(e.RHS, fld, min, max) |
| 59 | if lhs == nil { |
| 60 | return rhs |
| 61 | } |
| 62 | if rhs == nil { |
| 63 | return lhs |
| 64 | } |
| 65 | return dag.NewBinaryExpr("or", lhs, rhs) |
| 66 | case "or": |
| 67 | // For an "or", if we know both sides are prunable, then we can prune |
| 68 | // because either condition is required. So we "and" together the result |
| 69 | // when both sub-expressions are valid. |
| 70 | lhs := buildRangePruner(e.LHS, fld, min, max) |
| 71 | rhs := buildRangePruner(e.RHS, fld, min, max) |
| 72 | if lhs == nil || rhs == nil { |
| 73 | return nil |
| 74 | } |
| 75 | return dag.NewBinaryExpr("and", lhs, rhs) |
| 76 | case "==", "<", "<=", ">", ">=": |
| 77 | this, literal, op := literalComparison(e) |
| 78 | if this == nil || !fld.Equal(this.Path) { |
| 79 | return nil |
| 80 | } |
| 81 | // At this point, we know we can definitely run a pruning decision based |
| 82 | // on the literal value we found, the comparison op, and the lower/upper bounds. |
| 83 | return rangePrunerPred(op, literal, min, max) |
| 84 | default: |
| 85 | return nil |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | func rangePrunerPred(op string, literal *dag.PrimitiveExpr, min, max *dag.ThisExpr) *dag.BinaryExpr { |
| 90 | switch op { |
no test coverage detected