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  }