github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/sem/tree/like_test.go (about)

     1  // Copyright 2017 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package tree
    12  
    13  import (
    14  	"context"
    15  	"testing"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    18  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    19  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    20  )
    21  
    22  func TestLike(t *testing.T) {
    23  	defer leaktest.AfterTest(t)()
    24  	testData := []struct {
    25  		expr      string
    26  		pattern   string
    27  		matches   Datum
    28  		erroneous bool
    29  	}{
    30  		{``, `{`, DBoolFalse, false},
    31  		{``, `%%%%%`, DBoolTrue, false},
    32  		{`a[b]`, `%[[_]`, DBoolFalse, false},
    33  		{`+`, `++`, DBoolFalse, false},
    34  		{`a`, `}`, DBoolFalse, false},
    35  		{`a{}%`, `%\}\%`, DBoolTrue, false},
    36  		{`a{}%a`, `%\}\%\`, DBoolFalse, true},
    37  		{`G\n%`, `%__%`, DBoolTrue, false},
    38  		{``, `\`, DBoolFalse, false},
    39  		{`_%\b\n`, `%__`, DBoolTrue, false},
    40  		{`_\nL_`, `%_%`, DBoolTrue, false},
    41  	}
    42  	ctx := NewTestingEvalContext(cluster.MakeTestingClusterSettings())
    43  	for _, d := range testData {
    44  		if matches, err := matchLike(ctx, NewDString(d.expr), NewDString(d.pattern), false); err != nil && !d.erroneous {
    45  			t.Error(err)
    46  		} else if err == nil && d.erroneous {
    47  			t.Errorf("%s matching the pattern %s: expected to return an error",
    48  				d.expr,
    49  				d.pattern,
    50  			)
    51  		} else if matches != d.matches {
    52  			t.Errorf("%s matching the pattern %s: expected %v but found %v",
    53  				d.expr,
    54  				d.pattern,
    55  				d.matches,
    56  				matches,
    57  			)
    58  		}
    59  	}
    60  }
    61  
    62  func TestLikeEscape(t *testing.T) {
    63  	defer leaktest.AfterTest(t)()
    64  	testData := []struct {
    65  		expr      string
    66  		pattern   string
    67  		escape    string
    68  		matches   Datum
    69  		erroneous bool
    70  	}{
    71  		{``, `{`, string('\x7f'), DBoolFalse, false},
    72  		{``, `}`, `}`, DBoolFalse, false},
    73  		{``, `%%%%%`, ``, DBoolTrue, false},
    74  		{``, `%%%%%`, `\`, DBoolTrue, false},
    75  		{`a[b]`, `%[[_]`, `[`, DBoolTrue, false},
    76  		{`+`, `++`, `+`, DBoolTrue, false},
    77  		{`a`, `}`, `}`, DBoolFalse, true},
    78  		{`a{}%`, `%}}}%`, `}`, DBoolTrue, false},
    79  		{`BG_`, `%__`, `.`, DBoolTrue, false},
    80  		{`_%\b\n`, `%__`, ``, DBoolTrue, false},
    81  		{`_\nL_`, `%_%`, `{`, DBoolTrue, false},
    82  		{`_\nL_`, `%_%`, `%`, DBoolFalse, true},
    83  		{`\n\t`, `_%%_`, string('\x7f'), DBoolTrue, false},
    84  	}
    85  	ctx := NewTestingEvalContext(cluster.MakeTestingClusterSettings())
    86  	for _, d := range testData {
    87  		if matches, err := MatchLikeEscape(ctx, d.expr, d.pattern, d.escape, false); err != nil && !d.erroneous {
    88  			t.Error(err)
    89  		} else if err == nil && d.erroneous {
    90  			t.Errorf("%s matching the pattern %s with escape character %s: expected to return an error",
    91  				d.expr,
    92  				d.pattern,
    93  				d.escape,
    94  			)
    95  		} else if matches != d.matches {
    96  			t.Errorf("%s matching the pattern %s with escape character %s: expected %v but found %v",
    97  				d.expr,
    98  				d.pattern,
    99  				d.escape,
   100  				d.matches,
   101  				matches,
   102  			)
   103  		}
   104  	}
   105  }
   106  
   107  func TestSimilarEscape(t *testing.T) {
   108  	defer leaktest.AfterTest(t)()
   109  	testData := []struct {
   110  		expr     string
   111  		expected string
   112  	}{
   113  		{`test`, `test`},
   114  		{`test%`, `test.*`},
   115  		{`_test_`, `.test.`},
   116  		{`_%*`, `..**`},
   117  		{`[_%]*`, `[_%]*`},
   118  		{`.^$`, `\.\^\$`},
   119  		{`%(b|d)%`, `.*(?:b|d).*`},
   120  		{`se\"arch\"[\"]`, `se(arch)[\"]`},
   121  	}
   122  	for _, d := range testData {
   123  		s := SimilarEscape(d.expr)
   124  		if s != d.expected {
   125  			t.Errorf("%s: expected %s, but found %v", d.expr, d.expected, s)
   126  		}
   127  	}
   128  }
   129  
   130  var benchmarkLikePatterns = []string{
   131  	`test%`,
   132  	`%test%`,
   133  	`%test`,
   134  	``,
   135  	`%`,
   136  	`_`,
   137  	`test`,
   138  	`bad`,
   139  	`also\%`,
   140  }
   141  
   142  func benchmarkLike(b *testing.B, ctx *EvalContext, caseInsensitive bool) {
   143  	op := Like
   144  	if caseInsensitive {
   145  		op = ILike
   146  	}
   147  	likeFn, _ := CmpOps[op].LookupImpl(types.String, types.String)
   148  	iter := func() {
   149  		for _, p := range benchmarkLikePatterns {
   150  			if _, err := likeFn.Fn(ctx, NewDString("test"), NewDString(p)); err != nil {
   151  				b.Fatalf("LIKE evaluation failed with error: %v", err)
   152  			}
   153  		}
   154  	}
   155  	// Warm up cache, if applicable
   156  	iter()
   157  	b.ResetTimer()
   158  	for n := 0; n < b.N; n++ {
   159  		iter()
   160  	}
   161  }
   162  
   163  func BenchmarkLikeWithCache(b *testing.B) {
   164  	ctx := NewTestingEvalContext(cluster.MakeTestingClusterSettings())
   165  	ctx.ReCache = NewRegexpCache(len(benchmarkLikePatterns))
   166  	defer ctx.Mon.Stop(context.Background())
   167  
   168  	benchmarkLike(b, ctx, false)
   169  }
   170  
   171  func BenchmarkLikeWithoutCache(b *testing.B) {
   172  	evalCtx := NewTestingEvalContext(cluster.MakeTestingClusterSettings())
   173  	defer evalCtx.Stop(context.Background())
   174  
   175  	benchmarkLike(b, evalCtx, false)
   176  }
   177  
   178  func BenchmarkILikeWithCache(b *testing.B) {
   179  	ctx := NewTestingEvalContext(cluster.MakeTestingClusterSettings())
   180  	ctx.ReCache = NewRegexpCache(len(benchmarkLikePatterns))
   181  	defer ctx.Mon.Stop(context.Background())
   182  
   183  	benchmarkLike(b, ctx, true)
   184  }
   185  
   186  func BenchmarkILikeWithoutCache(b *testing.B) {
   187  	evalCtx := NewTestingEvalContext(cluster.MakeTestingClusterSettings())
   188  	defer evalCtx.Stop(context.Background())
   189  
   190  	benchmarkLike(b, evalCtx, true)
   191  }