github.com/vedadiyan/sqlparser@v1.0.0/pkg/sqlparser/predicate_rewriting.go (about) 1 /* 2 Copyright 2022 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package sqlparser 18 19 const ( 20 Changed RewriteState = true 21 NoChange RewriteState = false 22 ) 23 24 type RewriteState bool 25 26 // RewritePredicate walks the input AST and rewrites any boolean logic into a simpler form 27 // This simpler form is CNF plus logic for extracting predicates from OR, plus logic for turning ORs into IN 28 // Note: In order to re-plan, we need to empty the accumulated metadata in the AST, 29 // so ColName.Metadata will be nil:ed out as part of this rewrite 30 func RewritePredicate(ast SQLNode) SQLNode { 31 for { 32 finishedRewrite := true 33 ast = SafeRewrite(ast, nil, func(cursor *Cursor) bool { 34 if e, isExpr := cursor.node.(Expr); isExpr { 35 rewritten, state := simplifyExpression(e) 36 if state == Changed { 37 finishedRewrite = false 38 cursor.Replace(rewritten) 39 } 40 } 41 if col, isCol := cursor.node.(*ColName); isCol { 42 col.Metadata = nil 43 } 44 return true 45 }) 46 47 if finishedRewrite { 48 return ast 49 } 50 } 51 } 52 53 func simplifyExpression(expr Expr) (Expr, RewriteState) { 54 switch expr := expr.(type) { 55 case *NotExpr: 56 return simplifyNot(expr) 57 case *OrExpr: 58 return simplifyOr(expr) 59 case *XorExpr: 60 return simplifyXor(expr) 61 case *AndExpr: 62 return simplifyAnd(expr) 63 } 64 return expr, NoChange 65 } 66 67 func simplifyNot(expr *NotExpr) (Expr, RewriteState) { 68 switch child := expr.Expr.(type) { 69 case *NotExpr: 70 // NOT NOT A => A 71 return child.Expr, Changed 72 case *OrExpr: 73 // DeMorgan Rewriter 74 // NOT (A OR B) => NOT A AND NOT B 75 return &AndExpr{Right: &NotExpr{Expr: child.Right}, Left: &NotExpr{Expr: child.Left}}, Changed 76 case *AndExpr: 77 // DeMorgan Rewriter 78 // NOT (A AND B) => NOT A OR NOT B 79 return &OrExpr{Right: &NotExpr{Expr: child.Right}, Left: &NotExpr{Expr: child.Left}}, Changed 80 } 81 return expr, NoChange 82 } 83 84 // ExtractINFromOR will add additional predicated to an OR. 85 // this rewriter should not be used in a fixed point way, since it returns the original expression with additions, 86 // and it will therefor OOM before it stops rewriting 87 func ExtractINFromOR(expr *OrExpr) []Expr { 88 // we check if we have two comparisons on either side of the OR 89 // that we can add as an ANDed comparison. 90 // WHERE (a = 5 and B) or (a = 6 AND C) => 91 // WHERE (a = 5 AND B) OR (a = 6 AND C) AND a IN (5,6) 92 // This rewrite makes it possible to find a better route than Scatter if the `a` column has a helpful vindex 93 lftPredicates := SplitAndExpression(nil, expr.Left) 94 rgtPredicates := SplitAndExpression(nil, expr.Right) 95 var ins []Expr 96 for _, lft := range lftPredicates { 97 l, ok := lft.(*ComparisonExpr) 98 if !ok { 99 continue 100 } 101 for _, rgt := range rgtPredicates { 102 r, ok := rgt.(*ComparisonExpr) 103 if !ok { 104 continue 105 } 106 in, state := tryTurningOrIntoIn(l, r) 107 if state == Changed { 108 ins = append(ins, in) 109 } 110 } 111 } 112 113 return ins 114 } 115 116 func simplifyOr(expr *OrExpr) (Expr, RewriteState) { 117 or := expr 118 119 // first we search for ANDs and see how they can be simplified 120 land, lok := or.Left.(*AndExpr) 121 rand, rok := or.Right.(*AndExpr) 122 switch { 123 case lok && rok: 124 var a, b, c Expr 125 switch { 126 // (A and B) or (A and C) => A AND (B OR C) 127 case Equals.Expr(land.Left, rand.Left): 128 a, b, c = land.Left, land.Right, rand.Right 129 // (A and B) or (C and A) => A AND (B OR C) 130 case Equals.Expr(land.Left, rand.Right): 131 a, b, c = land.Left, land.Right, rand.Left 132 // (B and A) or (A and C) => A AND (B OR C) 133 case Equals.Expr(land.Right, rand.Left): 134 a, b, c = land.Right, land.Left, rand.Right 135 // (B and A) or (C and A) => A AND (B OR C) 136 case Equals.Expr(land.Right, rand.Right): 137 a, b, c = land.Right, land.Left, rand.Left 138 default: 139 return expr, NoChange 140 } 141 return &AndExpr{Left: a, Right: &OrExpr{Left: b, Right: c}}, Changed 142 case lok: 143 // Simplification 144 // (A AND B) OR A => A 145 if Equals.Expr(or.Right, land.Left) || Equals.Expr(or.Right, land.Right) { 146 return or.Right, Changed 147 } 148 // Distribution Law 149 // (A AND B) OR C => (A OR C) AND (B OR C) 150 return &AndExpr{Left: &OrExpr{Left: land.Left, Right: or.Right}, Right: &OrExpr{Left: land.Right, Right: or.Right}}, Changed 151 case rok: 152 // Simplification 153 // A OR (A AND B) => A 154 if Equals.Expr(or.Left, rand.Left) || Equals.Expr(or.Left, rand.Right) { 155 return or.Left, Changed 156 } 157 // Distribution Law 158 // C OR (A AND B) => (C OR A) AND (C OR B) 159 return &AndExpr{Left: &OrExpr{Left: or.Left, Right: rand.Left}, Right: &OrExpr{Left: or.Left, Right: rand.Right}}, Changed 160 } 161 162 // next, we want to try to turn multiple ORs into an IN when possible 163 lftCmp, lok := or.Left.(*ComparisonExpr) 164 rgtCmp, rok := or.Right.(*ComparisonExpr) 165 if lok && rok { 166 newExpr, rewritten := tryTurningOrIntoIn(lftCmp, rgtCmp) 167 if rewritten { 168 return newExpr, Changed 169 } 170 } 171 172 // Try to make distinct 173 return distinctOr(expr) 174 } 175 176 func tryTurningOrIntoIn(l, r *ComparisonExpr) (Expr, RewriteState) { 177 // looks for A = X OR A = Y and turns them into A IN (X, Y) 178 col, ok := l.Left.(*ColName) 179 if !ok || !Equals.Expr(col, r.Left) { 180 return nil, NoChange 181 } 182 183 var tuple ValTuple 184 185 switch l.Operator { 186 case EqualOp: 187 tuple = ValTuple{l.Right} 188 case InOp: 189 lft, ok := l.Right.(ValTuple) 190 if !ok { 191 return nil, NoChange 192 } 193 tuple = lft 194 default: 195 return nil, NoChange 196 } 197 198 switch r.Operator { 199 case EqualOp: 200 tuple = append(tuple, r.Right) 201 case InOp: 202 lft, ok := r.Right.(ValTuple) 203 if !ok { 204 return nil, NoChange 205 } 206 tuple = append(tuple, lft...) 207 default: 208 return nil, NoChange 209 } 210 211 return &ComparisonExpr{ 212 Operator: InOp, 213 Left: col, 214 Right: uniquefy(tuple), 215 }, Changed 216 } 217 218 func uniquefy(tuple ValTuple) (output ValTuple) { 219 outer: 220 for _, expr := range tuple { 221 for _, seen := range output { 222 if Equals.Expr(expr, seen) { 223 continue outer 224 } 225 } 226 output = append(output, expr) 227 } 228 return 229 } 230 231 func simplifyXor(expr *XorExpr) (Expr, RewriteState) { 232 // DeMorgan Rewriter 233 // (A XOR B) => (A OR B) AND NOT (A AND B) 234 return &AndExpr{Left: &OrExpr{Left: expr.Left, Right: expr.Right}, Right: &NotExpr{Expr: &AndExpr{Left: expr.Left, Right: expr.Right}}}, Changed 235 } 236 237 func simplifyAnd(expr *AndExpr) (Expr, RewriteState) { 238 res, rewritten := distinctAnd(expr) 239 if rewritten { 240 return res, rewritten 241 } 242 and := expr 243 if or, ok := and.Left.(*OrExpr); ok { 244 // Simplification 245 // (A OR B) AND A => A 246 if Equals.Expr(or.Left, and.Right) || Equals.Expr(or.Right, and.Right) { 247 return and.Right, Changed 248 } 249 } 250 if or, ok := and.Right.(*OrExpr); ok { 251 // Simplification 252 // A OR (A AND B) => A 253 if Equals.Expr(or.Left, and.Left) || Equals.Expr(or.Right, and.Left) { 254 return or.Left, Changed 255 } 256 } 257 258 return expr, NoChange 259 } 260 261 func distinctOr(in *OrExpr) (Expr, RewriteState) { 262 todo := []*OrExpr{in} 263 var leaves []Expr 264 for len(todo) > 0 { 265 curr := todo[0] 266 todo = todo[1:] 267 addAnd := func(in Expr) { 268 and, ok := in.(*OrExpr) 269 if ok { 270 todo = append(todo, and) 271 } else { 272 leaves = append(leaves, in) 273 } 274 } 275 addAnd(curr.Left) 276 addAnd(curr.Right) 277 } 278 original := len(leaves) 279 var predicates []Expr 280 281 outer1: 282 for len(leaves) > 0 { 283 curr := leaves[0] 284 leaves = leaves[1:] 285 for _, alreadyIn := range predicates { 286 if Equals.Expr(alreadyIn, curr) { 287 continue outer1 288 } 289 } 290 predicates = append(predicates, curr) 291 } 292 if original == len(predicates) { 293 return in, NoChange 294 } 295 var result Expr 296 for i, curr := range predicates { 297 if i == 0 { 298 result = curr 299 continue 300 } 301 result = &OrExpr{Left: result, Right: curr} 302 } 303 return result, Changed 304 } 305 306 func distinctAnd(in *AndExpr) (Expr, RewriteState) { 307 todo := []*AndExpr{in} 308 var leaves []Expr 309 for len(todo) > 0 { 310 curr := todo[0] 311 todo = todo[1:] 312 addAnd := func(in Expr) { 313 and, ok := in.(*AndExpr) 314 if ok { 315 todo = append(todo, and) 316 } else { 317 leaves = append(leaves, in) 318 } 319 } 320 addAnd(curr.Left) 321 addAnd(curr.Right) 322 } 323 original := len(leaves) 324 var predicates []Expr 325 326 outer1: 327 for len(leaves) > 0 { 328 curr := leaves[0] 329 leaves = leaves[1:] 330 for _, alreadyIn := range predicates { 331 if Equals.Expr(alreadyIn, curr) { 332 continue outer1 333 } 334 } 335 predicates = append(predicates, curr) 336 } 337 if original == len(predicates) { 338 return in, NoChange 339 } 340 var result Expr 341 for i, curr := range predicates { 342 if i == 0 { 343 result = curr 344 continue 345 } 346 result = &AndExpr{Left: result, Right: curr} 347 } 348 return result, Changed 349 }