@@ -20,11 +20,26 @@ import (
20
20
"vitess.io/vitess/go/vt/log"
21
21
)
22
22
23
+ // This is the number of OR expressions in a predicate that will disable the CNF
24
+ // rewrite because we don't want to send large queries to MySQL
25
+ const CNFOrLimit = 5
26
+
23
27
// RewritePredicate walks the input AST and rewrites any boolean logic into a simpler form
24
28
// This simpler form is CNF plus logic for extracting predicates from OR, plus logic for turning ORs into IN
25
29
// Note: In order to re-plan, we need to empty the accumulated metadata in the AST,
26
30
// so ColName.Metadata will be nil:ed out as part of this rewrite
27
31
func RewritePredicate (ast SQLNode ) SQLNode {
32
+ count := 0
33
+ _ = Walk (func (node SQLNode ) (bool , error ) {
34
+ if _ , isExpr := node .(* OrExpr ); isExpr {
35
+ count ++
36
+ }
37
+
38
+ return true , nil
39
+ }, ast )
40
+
41
+ allowCNF := count < CNFOrLimit
42
+
28
43
for {
29
44
printExpr (ast )
30
45
exprChanged := false
@@ -37,7 +52,7 @@ func RewritePredicate(ast SQLNode) SQLNode {
37
52
return true
38
53
}
39
54
40
- rewritten , state := simplifyExpression (e )
55
+ rewritten , state := simplifyExpression (e , allowCNF )
41
56
if ch , isChange := state .(changed ); isChange {
42
57
printRule (ch .rule , ch .exprMatched )
43
58
exprChanged = true
@@ -52,12 +67,12 @@ func RewritePredicate(ast SQLNode) SQLNode {
52
67
}
53
68
}
54
69
55
- func simplifyExpression (expr Expr ) (Expr , rewriteState ) {
70
+ func simplifyExpression (expr Expr , allowCNF bool ) (Expr , rewriteState ) {
56
71
switch expr := expr .(type ) {
57
72
case * NotExpr :
58
73
return simplifyNot (expr )
59
74
case * OrExpr :
60
- return simplifyOr (expr )
75
+ return simplifyOr (expr , allowCNF )
61
76
case * XorExpr :
62
77
return simplifyXor (expr )
63
78
case * AndExpr :
@@ -113,55 +128,66 @@ func ExtractINFromOR(expr *OrExpr) []Expr {
113
128
return uniquefy (ins )
114
129
}
115
130
116
- func simplifyOr (expr * OrExpr ) (Expr , rewriteState ) {
131
+ func simplifyOr (expr * OrExpr , allowCNF bool ) (Expr , rewriteState ) {
117
132
or := expr
118
133
119
134
// first we search for ANDs and see how they can be simplified
120
135
land , lok := or .Left .(* AndExpr )
121
136
rand , rok := or .Right .(* AndExpr )
122
- switch {
123
- case lok && rok :
137
+
138
+ if lok && rok {
124
139
// (<> AND <>) OR (<> AND <>)
125
140
var a , b , c Expr
126
141
var change changed
127
142
switch {
128
143
case Equals .Expr (land .Left , rand .Left ):
129
144
change = newChange ("(A and B) or (A and C) => A AND (B OR C)" , f (expr ))
130
145
a , b , c = land .Left , land .Right , rand .Right
146
+ return & AndExpr {Left : a , Right : & OrExpr {Left : b , Right : c }}, change
131
147
case Equals .Expr (land .Left , rand .Right ):
132
148
change = newChange ("(A and B) or (C and A) => A AND (B OR C)" , f (expr ))
133
149
a , b , c = land .Left , land .Right , rand .Left
150
+ return & AndExpr {Left : a , Right : & OrExpr {Left : b , Right : c }}, change
134
151
case Equals .Expr (land .Right , rand .Left ):
135
152
change = newChange ("(B and A) or (A and C) => A AND (B OR C)" , f (expr ))
136
153
a , b , c = land .Right , land .Left , rand .Right
154
+ return & AndExpr {Left : a , Right : & OrExpr {Left : b , Right : c }}, change
137
155
case Equals .Expr (land .Right , rand .Right ):
138
156
change = newChange ("(B and A) or (C and A) => A AND (B OR C)" , f (expr ))
139
157
a , b , c = land .Right , land .Left , rand .Left
140
- default :
141
- return expr , noChange {}
158
+ return & AndExpr {Left : a , Right : & OrExpr {Left : b , Right : c }}, change
142
159
}
143
- return & AndExpr {Left : a , Right : & OrExpr {Left : b , Right : c }}, change
144
- case lok :
145
- // (<> AND <>) OR <>
160
+ }
161
+
162
+ // (<> AND <>) OR <>
163
+ if lok {
146
164
// Simplification
147
165
if Equals .Expr (or .Right , land .Left ) || Equals .Expr (or .Right , land .Right ) {
148
166
return or .Right , newChange ("(A AND B) OR A => A" , f (expr ))
149
167
}
150
- // Distribution Law
151
- return & AndExpr {Left : & OrExpr {Left : land .Left , Right : or .Right }, Right : & OrExpr {Left : land .Right , Right : or .Right }},
152
- newChange ("(A AND B) OR C => (A OR C) AND (B OR C)" , f (expr ))
153
- case rok :
154
- // <> OR (<> AND <>)
168
+
169
+ if allowCNF {
170
+ // Distribution Law
171
+ return & AndExpr {Left : & OrExpr {Left : land .Left , Right : or .Right }, Right : & OrExpr {Left : land .Right , Right : or .Right }},
172
+ newChange ("(A AND B) OR C => (A OR C) AND (B OR C)" , f (expr ))
173
+ }
174
+ }
175
+
176
+ // <> OR (<> AND <>)
177
+ if rok {
155
178
// Simplification
156
179
if Equals .Expr (or .Left , rand .Left ) || Equals .Expr (or .Left , rand .Right ) {
157
180
return or .Left , newChange ("A OR (A AND B) => A" , f (expr ))
158
181
}
159
- // Distribution Law
160
- return & AndExpr {
161
- Left : & OrExpr {Left : or .Left , Right : rand .Left },
162
- Right : & OrExpr {Left : or .Left , Right : rand .Right },
163
- },
164
- newChange ("C OR (A AND B) => (C OR A) AND (C OR B)" , f (expr ))
182
+
183
+ if allowCNF {
184
+ // Distribution Law
185
+ return & AndExpr {
186
+ Left : & OrExpr {Left : or .Left , Right : rand .Left },
187
+ Right : & OrExpr {Left : or .Left , Right : rand .Right },
188
+ },
189
+ newChange ("C OR (A AND B) => (C OR A) AND (C OR B)" , f (expr ))
190
+ }
165
191
}
166
192
167
193
// next, we want to try to turn multiple ORs into an IN when possible
@@ -257,7 +283,6 @@ func simplifyAnd(expr *AndExpr) (Expr, rewriteState) {
257
283
and := expr
258
284
if or , ok := and .Left .(* OrExpr ); ok {
259
285
// Simplification
260
-
261
286
if Equals .Expr (or .Left , and .Right ) {
262
287
return and .Right , newChange ("(A OR B) AND A => A" , f (expr ))
263
288
}
0 commit comments