github.com/team-ide/go-dialect@v1.9.20/vitess/sqlparser/random_expr.go (about) 1 /* 2 Copyright 2020 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 import ( 20 "fmt" 21 "math/rand" 22 ) 23 24 // This file is used to generate random expressions to be used for testing 25 26 func newGenerator(seed int64, maxDepth int) *generator { 27 g := generator{ 28 seed: seed, 29 r: rand.New(rand.NewSource(seed)), 30 maxDepth: maxDepth, 31 } 32 return &g 33 } 34 35 type generator struct { 36 seed int64 37 r *rand.Rand 38 depth int 39 maxDepth int 40 } 41 42 // enter should be called whenever we are producing an intermediate node. it should be followed by a `defer g.exit()` 43 func (g *generator) enter() { 44 g.depth++ 45 } 46 47 // exit should be called when exiting an intermediate node 48 func (g *generator) exit() { 49 g.depth-- 50 } 51 52 // atMaxDepth returns true if we have reached the maximum allowed depth or the expression tree 53 func (g *generator) atMaxDepth() bool { 54 return g.depth >= g.maxDepth 55 } 56 57 /* Creates a random expression. It builds an expression tree using the following constructs: 58 - true/false 59 - AND/OR/NOT 60 - string literalrs, numeric literals (-/+ 1000) 61 - =, >, <, >=, <=, <=>, != 62 - &, |, ^, +, -, *, /, div, %, <<, >> 63 - IN, BETWEEN and CASE 64 - IS NULL, IS NOT NULL, IS TRUE, IS NOT TRUE, IS FALSE, IS NOT FALSE 65 66 Note: It's important to update this method so that it produces all expressions that need precedence checking. 67 It's currently missing function calls and string operators 68 */ 69 func (g *generator) expression() Expr { 70 if g.randomBool() { 71 return g.booleanExpr() 72 } 73 options := []exprF{ 74 func() Expr { return g.intExpr() }, 75 func() Expr { return g.stringExpr() }, 76 func() Expr { return g.booleanExpr() }, 77 } 78 79 return g.randomOf(options) 80 } 81 82 func (g *generator) booleanExpr() Expr { 83 if g.atMaxDepth() { 84 return g.booleanLiteral() 85 } 86 87 options := []exprF{ 88 func() Expr { return g.andExpr() }, 89 func() Expr { return g.xorExpr() }, 90 func() Expr { return g.orExpr() }, 91 func() Expr { return g.comparison(g.intExpr) }, 92 func() Expr { return g.comparison(g.stringExpr) }, 93 //func() Expr { return g.comparison(g.booleanExpr) }, // this is not accepted by the parser 94 func() Expr { return g.inExpr() }, 95 func() Expr { return g.between() }, 96 func() Expr { return g.isExpr() }, 97 func() Expr { return g.notExpr() }, 98 func() Expr { return g.likeExpr() }, 99 } 100 101 return g.randomOf(options) 102 } 103 104 func (g *generator) intExpr() Expr { 105 if g.atMaxDepth() { 106 return g.intLiteral() 107 } 108 109 options := []exprF{ 110 func() Expr { return g.arithmetic() }, 111 func() Expr { return g.intLiteral() }, 112 func() Expr { return g.caseExpr(g.intExpr) }, 113 } 114 115 return g.randomOf(options) 116 } 117 118 func (g *generator) booleanLiteral() Expr { 119 return BoolVal(g.randomBool()) 120 } 121 122 func (g *generator) randomBool() bool { 123 return g.r.Float32() < 0.5 124 } 125 126 func (g *generator) intLiteral() Expr { 127 t := fmt.Sprintf("%d", g.r.Intn(1000)-g.r.Intn((1000))) 128 129 return NewIntLiteral(t) 130 } 131 132 var words = []string{"ox", "ant", "ape", "asp", "bat", "bee", "boa", "bug", "cat", "cod", "cow", "cub", "doe", "dog", "eel", "eft", "elf", "elk", "emu", "ewe", "fly", "fox", "gar", "gnu", "hen", "hog", "imp", "jay", "kid", "kit", "koi", "lab", "man", "owl", "pig", "pug", "pup", "ram", "rat", "ray", "yak", "bass", "bear", "bird", "boar", "buck", "bull", "calf", "chow", "clam", "colt", "crab", "crow", "dane", "deer", "dodo", "dory", "dove", "drum", "duck", "fawn", "fish", "flea", "foal", "fowl", "frog", "gnat", "goat", "grub", "gull", "hare", "hawk", "ibex", "joey", "kite", "kiwi", "lamb", "lark", "lion", "loon", "lynx", "mako", "mink", "mite", "mole", "moth", "mule", "mutt", "newt", "orca", "oryx", "pika", "pony", "puma", "seal", "shad", "slug", "sole", "stag", "stud", "swan", "tahr", "teal", "tick", "toad", "tuna", "wasp", "wolf", "worm", "wren", "yeti", "adder", "akita", "alien", "aphid", "bison", "boxer", "bream", "bunny", "burro", "camel", "chimp", "civet", "cobra", "coral", "corgi", "crane", "dingo", "drake", "eagle", "egret", "filly", "finch", "gator", "gecko", "ghost", "ghoul", "goose", "guppy", "heron", "hippo", "horse", "hound", "husky", "hyena", "koala", "krill", "leech", "lemur", "liger", "llama", "louse", "macaw", "midge", "molly", "moose", "moray", "mouse", "panda", "perch", "prawn", "quail", "racer", "raven", "rhino", "robin", "satyr", "shark", "sheep", "shrew", "skink", "skunk", "sloth", "snail", "snake", "snipe", "squid", "stork", "swift", "swine", "tapir", "tetra", "tiger", "troll", "trout", "viper", "wahoo", "whale", "zebra", "alpaca", "amoeba", "baboon", "badger", "beagle", "bedbug", "beetle", "bengal", "bobcat", "caiman", "cattle", "cicada", "collie", "condor", "cougar", "coyote", "dassie", "donkey", "dragon", "earwig", "falcon", "feline", "ferret", "gannet", "gibbon", "glider", "goblin", "gopher", "grouse", "guinea", "hermit", "hornet", "iguana", "impala", "insect", "jackal", "jaguar", "jennet", "kitten", "kodiak", "lizard", "locust", "maggot", "magpie", "mammal", "mantis", "marlin", "marmot", "marten", "martin", "mayfly", "minnow", "monkey", "mullet", "muskox", "ocelot", "oriole", "osprey", "oyster", "parrot", "pigeon", "piglet", "poodle", "possum", "python", "quagga", "rabbit", "raptor", "rodent", "roughy", "salmon", "sawfly", "serval", "shiner", "shrimp", "spider", "sponge", "tarpon", "thrush", "tomcat", "toucan", "turkey", "turtle", "urchin", "vervet", "walrus", "weasel", "weevil", "wombat", "anchovy", "anemone", "bluejay", "buffalo", "bulldog", "buzzard", "caribou", "catfish", "chamois", "cheetah", "chicken", "chigger", "cowbird", "crappie", "crawdad", "cricket", "dogfish", "dolphin", "firefly", "garfish", "gazelle", "gelding", "giraffe", "gobbler", "gorilla", "goshawk", "grackle", "griffon", "grizzly", "grouper", "haddock", "hagfish", "halibut", "hamster", "herring", "jackass", "javelin", "jawfish", "jaybird", "katydid", "ladybug", "lamprey", "lemming", "leopard", "lioness", "lobster", "macaque", "mallard", "mammoth", "manatee", "mastiff", "meerkat", "mollusk", "monarch", "mongrel", "monitor", "monster", "mudfish", "muskrat", "mustang", "narwhal", "oarfish", "octopus", "opossum", "ostrich", "panther", "peacock", "pegasus", "pelican", "penguin", "phoenix", "piranha", "polecat", "primate", "quetzal", "raccoon", "rattler", "redbird", "redfish", "reptile", "rooster", "sawfish", "sculpin", "seagull", "skylark", "snapper", "spaniel", "sparrow", "sunbeam", "sunbird", "sunfish", "tadpole", "termite", "terrier", "unicorn", "vulture", "wallaby", "walleye", "warthog", "whippet", "wildcat", "aardvark", "airedale", "albacore", "anteater", "antelope", "arachnid", "barnacle", "basilisk", "blowfish", "bluebird", "bluegill", "bonefish", "bullfrog", "cardinal", "chipmunk", "cockatoo", "crayfish", "dinosaur", "doberman", "duckling", "elephant", "escargot", "flamingo", "flounder", "foxhound", "glowworm", "goldfish", "grubworm", "hedgehog", "honeybee", "hookworm", "humpback", "kangaroo", "killdeer", "kingfish", "labrador", "lacewing", "ladybird", "lionfish", "longhorn", "mackerel", "malamute", "marmoset", "mastodon", "moccasin", "mongoose", "monkfish", "mosquito", "pangolin", "parakeet", "pheasant", "pipefish", "platypus", "polliwog", "porpoise", "reindeer", "ringtail", "sailfish", "scorpion", "seahorse", "seasnail", "sheepdog", "shepherd", "silkworm", "squirrel", "stallion", "starfish", "starling", "stingray", "stinkbug", "sturgeon", "terrapin", "titmouse", "tortoise", "treefrog", "werewolf", "woodcock"} 133 134 func (g *generator) stringLiteral() Expr { 135 return NewStrLiteral(g.randomOfS(words)) 136 } 137 138 func (g *generator) stringExpr() Expr { 139 if g.atMaxDepth() { 140 return g.stringLiteral() 141 } 142 143 options := []exprF{ 144 func() Expr { return g.stringLiteral() }, 145 func() Expr { return g.caseExpr(g.stringExpr) }, 146 } 147 148 return g.randomOf(options) 149 } 150 151 func (g *generator) likeExpr() Expr { 152 g.enter() 153 defer g.exit() 154 return &ComparisonExpr{ 155 Operator: LikeOp, 156 Left: g.stringExpr(), 157 Right: g.stringExpr(), 158 } 159 } 160 161 var comparisonOps = []ComparisonExprOperator{EqualOp, LessThanOp, GreaterThanOp, LessEqualOp, GreaterEqualOp, NotEqualOp, NullSafeEqualOp} 162 163 func (g *generator) comparison(f func() Expr) Expr { 164 g.enter() 165 defer g.exit() 166 167 cmp := &ComparisonExpr{ 168 Operator: comparisonOps[g.r.Intn(len(comparisonOps))], 169 Left: f(), 170 Right: f(), 171 } 172 return cmp 173 } 174 175 func (g *generator) caseExpr(valueF func() Expr) Expr { 176 g.enter() 177 defer g.exit() 178 179 var exp Expr 180 var elseExpr Expr 181 if g.randomBool() { 182 exp = valueF() 183 } 184 if g.randomBool() { 185 elseExpr = valueF() 186 } 187 188 size := g.r.Intn(5) + 2 189 var whens []*When 190 for i := 0; i < size; i++ { 191 var cond Expr 192 if exp == nil { 193 cond = g.booleanExpr() 194 } else { 195 cond = g.expression() 196 } 197 198 whens = append(whens, &When{ 199 Cond: cond, 200 Val: g.expression(), 201 }) 202 } 203 204 return &CaseExpr{ 205 Expr: exp, 206 Whens: whens, 207 Else: elseExpr, 208 } 209 } 210 211 var arithmeticOps = []BinaryExprOperator{BitAndOp, BitOrOp, BitXorOp, PlusOp, MinusOp, MultOp, DivOp, IntDivOp, ModOp, ShiftRightOp, ShiftLeftOp} 212 213 func (g *generator) arithmetic() Expr { 214 g.enter() 215 defer g.exit() 216 217 op := arithmeticOps[g.r.Intn(len(arithmeticOps))] 218 219 return &BinaryExpr{ 220 Operator: op, 221 Left: g.intExpr(), 222 Right: g.intExpr(), 223 } 224 } 225 226 type exprF func() Expr 227 228 func (g *generator) randomOf(options []exprF) Expr { 229 return options[g.r.Intn(len(options))]() 230 } 231 232 func (g *generator) randomOfS(options []string) string { 233 return options[g.r.Intn(len(options))] 234 } 235 236 func (g *generator) andExpr() Expr { 237 g.enter() 238 defer g.exit() 239 return &AndExpr{ 240 Left: g.booleanExpr(), 241 Right: g.booleanExpr(), 242 } 243 } 244 245 func (g *generator) orExpr() Expr { 246 g.enter() 247 defer g.exit() 248 return &OrExpr{ 249 Left: g.booleanExpr(), 250 Right: g.booleanExpr(), 251 } 252 } 253 254 func (g *generator) xorExpr() Expr { 255 g.enter() 256 defer g.exit() 257 return &XorExpr{ 258 Left: g.booleanExpr(), 259 Right: g.booleanExpr(), 260 } 261 } 262 263 func (g *generator) notExpr() Expr { 264 g.enter() 265 defer g.exit() 266 return &NotExpr{g.booleanExpr()} 267 } 268 269 func (g *generator) inExpr() Expr { 270 g.enter() 271 defer g.exit() 272 273 expr := g.intExpr() 274 size := g.r.Intn(5) + 2 275 tuples := ValTuple{} 276 for i := 0; i < size; i++ { 277 tuples = append(tuples, g.intExpr()) 278 } 279 op := InOp 280 if g.randomBool() { 281 op = NotInOp 282 } 283 284 return &ComparisonExpr{ 285 Operator: op, 286 Left: expr, 287 Right: tuples, 288 } 289 } 290 291 func (g *generator) between() Expr { 292 g.enter() 293 defer g.exit() 294 295 var IsBetween bool 296 if g.randomBool() { 297 IsBetween = true 298 } else { 299 IsBetween = false 300 } 301 302 return &BetweenExpr{ 303 IsBetween: IsBetween, 304 Left: g.intExpr(), 305 From: g.intExpr(), 306 To: g.intExpr(), 307 } 308 } 309 310 func (g *generator) isExpr() Expr { 311 g.enter() 312 defer g.exit() 313 314 ops := []IsExprOperator{IsNullOp, IsNotNullOp, IsTrueOp, IsNotTrueOp, IsFalseOp, IsNotFalseOp} 315 316 return &IsExpr{ 317 Right: ops[g.r.Intn(len(ops))], 318 Left: g.booleanExpr(), 319 } 320 }