vitess.io/vitess@v0.16.2/go/vt/sqlparser/token_test.go (about)

     1  /*
     2  Copyright 2019 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  	"testing"
    22  
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  func TestLiteralID(t *testing.T) {
    27  	testcases := []struct {
    28  		in  string
    29  		id  int
    30  		out string
    31  	}{{
    32  		in:  "`aa`",
    33  		id:  ID,
    34  		out: "aa",
    35  	}, {
    36  		in:  "```a```",
    37  		id:  ID,
    38  		out: "`a`",
    39  	}, {
    40  		in:  "`a``b`",
    41  		id:  ID,
    42  		out: "a`b",
    43  	}, {
    44  		in:  "`a``b`c",
    45  		id:  ID,
    46  		out: "a`b",
    47  	}, {
    48  		in:  "`a``b",
    49  		id:  LEX_ERROR,
    50  		out: "a`b",
    51  	}, {
    52  		in:  "`a``b``",
    53  		id:  LEX_ERROR,
    54  		out: "a`b`",
    55  	}, {
    56  		in:  "``",
    57  		id:  LEX_ERROR,
    58  		out: "",
    59  	}, {
    60  		in:  "@x",
    61  		id:  AT_ID,
    62  		out: "x",
    63  	}, {
    64  		in:  "@@x",
    65  		id:  AT_AT_ID,
    66  		out: "x",
    67  	}, {
    68  		in:  "@@`x y`",
    69  		id:  AT_AT_ID,
    70  		out: "x y",
    71  	}, {
    72  		in:  "@@`@x @y`",
    73  		id:  AT_AT_ID,
    74  		out: "@x @y",
    75  	}}
    76  
    77  	for _, tcase := range testcases {
    78  		t.Run(tcase.in, func(t *testing.T) {
    79  			tkn := NewStringTokenizer(tcase.in)
    80  			id, out := tkn.Scan()
    81  			require.Equal(t, tcase.id, id)
    82  			require.Equal(t, tcase.out, string(out))
    83  		})
    84  	}
    85  }
    86  
    87  func tokenName(id int) string {
    88  	if id == STRING {
    89  		return "STRING"
    90  	} else if id == LEX_ERROR {
    91  		return "LEX_ERROR"
    92  	}
    93  	return fmt.Sprintf("%d", id)
    94  }
    95  
    96  func TestString(t *testing.T) {
    97  	testcases := []struct {
    98  		in   string
    99  		id   int
   100  		want string
   101  	}{{
   102  		in:   "''",
   103  		id:   STRING,
   104  		want: "",
   105  	}, {
   106  		in:   "''''",
   107  		id:   STRING,
   108  		want: "'",
   109  	}, {
   110  		in:   "'hello'",
   111  		id:   STRING,
   112  		want: "hello",
   113  	}, {
   114  		in:   "'\\n'",
   115  		id:   STRING,
   116  		want: "\n",
   117  	}, {
   118  		in:   "'\\nhello\\n'",
   119  		id:   STRING,
   120  		want: "\nhello\n",
   121  	}, {
   122  		in:   "'a''b'",
   123  		id:   STRING,
   124  		want: "a'b",
   125  	}, {
   126  		in:   "'a\\'b'",
   127  		id:   STRING,
   128  		want: "a'b",
   129  	}, {
   130  		in:   "'\\'",
   131  		id:   LEX_ERROR,
   132  		want: "'",
   133  	}, {
   134  		in:   "'",
   135  		id:   LEX_ERROR,
   136  		want: "",
   137  	}, {
   138  		in:   "'hello\\'",
   139  		id:   LEX_ERROR,
   140  		want: "hello'",
   141  	}, {
   142  		in:   "'hello",
   143  		id:   LEX_ERROR,
   144  		want: "hello",
   145  	}, {
   146  		in:   "'hello\\",
   147  		id:   LEX_ERROR,
   148  		want: "hello",
   149  	}}
   150  
   151  	for _, tcase := range testcases {
   152  		t.Run(tcase.in, func(t *testing.T) {
   153  			id, got := NewStringTokenizer(tcase.in).Scan()
   154  			require.Equal(t, tcase.id, id, "Scan(%q) = (%s), want (%s)", tcase.in, tokenName(id), tokenName(tcase.id))
   155  			require.Equal(t, tcase.want, string(got))
   156  		})
   157  	}
   158  }
   159  
   160  func TestSplitStatement(t *testing.T) {
   161  	testcases := []struct {
   162  		in  string
   163  		sql string
   164  		rem string
   165  	}{{
   166  		in:  "select * from table",
   167  		sql: "select * from table",
   168  	}, {
   169  		in:  "select * from table; ",
   170  		sql: "select * from table",
   171  		rem: " ",
   172  	}, {
   173  		in:  "select * from table; select * from table2;",
   174  		sql: "select * from table",
   175  		rem: " select * from table2;",
   176  	}, {
   177  		in:  "select * from /* comment */ table;",
   178  		sql: "select * from /* comment */ table",
   179  	}, {
   180  		in:  "select * from /* comment ; */ table;",
   181  		sql: "select * from /* comment ; */ table",
   182  	}, {
   183  		in:  "select * from table where semi = ';';",
   184  		sql: "select * from table where semi = ';'",
   185  	}, {
   186  		in:  "-- select * from table",
   187  		sql: "-- select * from table",
   188  	}, {
   189  		in:  " ",
   190  		sql: " ",
   191  	}, {
   192  		in:  "",
   193  		sql: "",
   194  	}}
   195  
   196  	for _, tcase := range testcases {
   197  		t.Run(tcase.in, func(t *testing.T) {
   198  			sql, rem, err := SplitStatement(tcase.in)
   199  			if err != nil {
   200  				t.Errorf("EndOfStatementPosition(%s): ERROR: %v", tcase.in, err)
   201  				return
   202  			}
   203  
   204  			if tcase.sql != sql {
   205  				t.Errorf("EndOfStatementPosition(%s) got sql \"%s\" want \"%s\"", tcase.in, sql, tcase.sql)
   206  			}
   207  
   208  			if tcase.rem != rem {
   209  				t.Errorf("EndOfStatementPosition(%s) got remainder \"%s\" want \"%s\"", tcase.in, rem, tcase.rem)
   210  			}
   211  		})
   212  	}
   213  }
   214  
   215  func TestVersion(t *testing.T) {
   216  	testcases := []struct {
   217  		version string
   218  		in      string
   219  		id      []int
   220  	}{{
   221  		version: "50709",
   222  		in:      "/*!80102 SELECT*/ FROM IN EXISTS",
   223  		id:      []int{FROM, IN, EXISTS, 0},
   224  	}, {
   225  		version: "80101",
   226  		in:      "/*!80102 SELECT*/ FROM IN EXISTS",
   227  		id:      []int{FROM, IN, EXISTS, 0},
   228  	}, {
   229  		version: "80201",
   230  		in:      "/*!80102 SELECT*/ FROM IN EXISTS",
   231  		id:      []int{SELECT, FROM, IN, EXISTS, 0},
   232  	}, {
   233  		version: "80102",
   234  		in:      "/*!80102 SELECT*/ FROM IN EXISTS",
   235  		id:      []int{SELECT, FROM, IN, EXISTS, 0},
   236  	}}
   237  
   238  	for _, tcase := range testcases {
   239  		t.Run(tcase.version+"_"+tcase.in, func(t *testing.T) {
   240  			mySQLParserVersion = tcase.version
   241  			tok := NewStringTokenizer(tcase.in)
   242  			for _, expectedID := range tcase.id {
   243  				id, _ := tok.Scan()
   244  				require.Equal(t, expectedID, id)
   245  			}
   246  		})
   247  	}
   248  }
   249  
   250  func TestExtractMySQLComment(t *testing.T) {
   251  	testcases := []struct {
   252  		comment string
   253  		version string
   254  	}{{
   255  		comment: "/*!50108 SELECT * FROM */",
   256  		version: "50108",
   257  	}, {
   258  		comment: "/*!5018 SELECT * FROM */",
   259  		version: "",
   260  	}, {
   261  		comment: "/*!SELECT * FROM */",
   262  		version: "",
   263  	}}
   264  
   265  	for _, tcase := range testcases {
   266  		t.Run(tcase.version, func(t *testing.T) {
   267  			output, _ := ExtractMysqlComment(tcase.comment)
   268  			require.Equal(t, tcase.version, output)
   269  		})
   270  	}
   271  }
   272  
   273  func TestIntegerAndID(t *testing.T) {
   274  	testcases := []struct {
   275  		in  string
   276  		id  int
   277  		out string
   278  	}{{
   279  		in: "334",
   280  		id: INTEGRAL,
   281  	}, {
   282  		in: "33.4",
   283  		id: DECIMAL,
   284  	}, {
   285  		in: "0x33",
   286  		id: HEXNUM,
   287  	}, {
   288  		in: "33e4",
   289  		id: FLOAT,
   290  	}, {
   291  		in: "33.4e-3",
   292  		id: FLOAT,
   293  	}, {
   294  		in: "33t4",
   295  		id: ID,
   296  	}, {
   297  		in: "0x2et3",
   298  		id: ID,
   299  	}, {
   300  		in:  "3e2t3",
   301  		id:  LEX_ERROR,
   302  		out: "3e2",
   303  	}, {
   304  		in:  "3.2t",
   305  		id:  LEX_ERROR,
   306  		out: "3.2",
   307  	}}
   308  
   309  	for _, tcase := range testcases {
   310  		t.Run(tcase.in, func(t *testing.T) {
   311  			tkn := NewStringTokenizer(tcase.in)
   312  			id, out := tkn.Scan()
   313  			require.Equal(t, tcase.id, id)
   314  			expectedOut := tcase.out
   315  			if expectedOut == "" {
   316  				expectedOut = tcase.in
   317  			}
   318  			require.Equal(t, expectedOut, out)
   319  		})
   320  	}
   321  }