storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/s3select/sql/parser_test.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2019 MinIO, Inc. 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 sql 18 19 import ( 20 "bytes" 21 "testing" 22 23 "github.com/alecthomas/participle" 24 "github.com/alecthomas/participle/lexer" 25 ) 26 27 func TestJSONPathElement(t *testing.T) { 28 p := participle.MustBuild( 29 &JSONPathElement{}, 30 participle.Lexer(sqlLexer), 31 participle.CaseInsensitive("Keyword"), 32 participle.CaseInsensitive("Timeword"), 33 ) 34 35 j := JSONPathElement{} 36 cases := []string{ 37 // Key 38 "['name']", ".name", `."name"`, 39 40 // Index 41 "[2]", "[0]", "[100]", 42 43 // Object wilcard 44 ".*", 45 46 // array wildcard 47 "[*]", 48 } 49 for i, tc := range cases { 50 err := p.ParseString(tc, &j) 51 if err != nil { 52 t.Fatalf("%d: %v", i, err) 53 } 54 // repr.Println(j, repr.Indent(" "), repr.OmitEmpty(true)) 55 } 56 } 57 58 func TestJSONPath(t *testing.T) { 59 p := participle.MustBuild( 60 &JSONPath{}, 61 participle.Lexer(sqlLexer), 62 participle.CaseInsensitive("Keyword"), 63 participle.CaseInsensitive("Timeword"), 64 ) 65 66 j := JSONPath{} 67 cases := []string{ 68 "S3Object", 69 "S3Object.id", 70 "S3Object.book.title", 71 "S3Object.id[1]", 72 "S3Object.id['abc']", 73 "S3Object.id['ab']", 74 "S3Object.words.*.id", 75 "S3Object.words.name[*].val", 76 "S3Object.words.name[*].val[*]", 77 "S3Object.words.name[*].val.*", 78 } 79 for i, tc := range cases { 80 err := p.ParseString(tc, &j) 81 if err != nil { 82 t.Fatalf("%d: %v", i, err) 83 } 84 // repr.Println(j, repr.Indent(" "), repr.OmitEmpty(true)) 85 } 86 87 } 88 89 func TestIdentifierParsing(t *testing.T) { 90 p := participle.MustBuild( 91 &Identifier{}, 92 participle.Lexer(sqlLexer), 93 participle.CaseInsensitive("Keyword"), 94 ) 95 96 id := Identifier{} 97 validCases := []string{ 98 "a", 99 "_a", 100 "abc_a", 101 "a2", 102 `"abc"`, 103 `"abc\a""ac"`, 104 } 105 for i, tc := range validCases { 106 err := p.ParseString(tc, &id) 107 if err != nil { 108 t.Fatalf("%d: %v", i, err) 109 } 110 // repr.Println(id, repr.Indent(" "), repr.OmitEmpty(true)) 111 } 112 113 invalidCases := []string{ 114 "+a", 115 "-a", 116 "1a", 117 `"ab`, 118 `abc"`, 119 `aa""a`, 120 `"a"a"`, 121 } 122 for i, tc := range invalidCases { 123 err := p.ParseString(tc, &id) 124 if err == nil { 125 t.Fatalf("%d: %v", i, err) 126 } 127 // fmt.Println(tc, err) 128 } 129 } 130 131 func TestLiteralStringParsing(t *testing.T) { 132 var k ObjectKey 133 p := participle.MustBuild( 134 &ObjectKey{}, 135 participle.Lexer(sqlLexer), 136 participle.CaseInsensitive("Keyword"), 137 ) 138 139 validCases := []string{ 140 "['abc']", 141 "['ab''c']", 142 "['a''b''c']", 143 "['abc-x_1##@(*&(#*))/\\']", 144 } 145 for i, tc := range validCases { 146 err := p.ParseString(tc, &k) 147 if err != nil { 148 t.Fatalf("%d: %v", i, err) 149 } 150 if string(*k.Lit) == "" { 151 t.Fatalf("Incorrect parse %#v", k) 152 } 153 // repr.Println(k, repr.Indent(" "), repr.OmitEmpty(true)) 154 } 155 156 invalidCases := []string{ 157 "['abc'']", 158 "['-abc'sc']", 159 "[abc']", 160 "['ac]", 161 } 162 for i, tc := range invalidCases { 163 err := p.ParseString(tc, &k) 164 if err == nil { 165 t.Fatalf("%d: %v", i, err) 166 } 167 // fmt.Println(tc, err) 168 } 169 } 170 171 func TestFunctionParsing(t *testing.T) { 172 var fex FuncExpr 173 p := participle.MustBuild( 174 &FuncExpr{}, 175 participle.Lexer(sqlLexer), 176 participle.CaseInsensitive("Keyword"), 177 participle.CaseInsensitive("Timeword"), 178 ) 179 180 validCases := []string{ 181 "count(*)", 182 "sum(2 + s.id)", 183 "sum(t)", 184 "avg(s.id[1])", 185 "coalesce(s.id[1], 2, 2 + 3)", 186 187 "cast(s as string)", 188 "cast(s AS INT)", 189 "cast(s as DECIMAL)", 190 "extract(YEAR from '2018-01-09')", 191 "extract(month from '2018-01-09')", 192 193 "extract(hour from '2018-01-09')", 194 "extract(day from '2018-01-09')", 195 "substring('abcd' from 2 for 2)", 196 "substring('abcd' from 2)", 197 "substring('abcd' , 2 , 2)", 198 199 "substring('abcd' , 22 )", 200 "trim(' aab ')", 201 "trim(leading from ' aab ')", 202 "trim(trailing from ' aab ')", 203 "trim(both from ' aab ')", 204 205 "trim(both '12' from ' aab ')", 206 "trim(leading '12' from ' aab ')", 207 "trim(trailing '12' from ' aab ')", 208 "count(23)", 209 } 210 for i, tc := range validCases { 211 err := p.ParseString(tc, &fex) 212 if err != nil { 213 t.Fatalf("%d: %v", i, err) 214 } 215 // repr.Println(fex, repr.Indent(" "), repr.OmitEmpty(true)) 216 } 217 } 218 219 func TestSqlLexer(t *testing.T) { 220 // s := bytes.NewBuffer([]byte("s.['name'].*.[*].abc.[\"abc\"]")) 221 s := bytes.NewBuffer([]byte("S3Object.words.*.id")) 222 // s := bytes.NewBuffer([]byte("COUNT(Id)")) 223 lex, err := sqlLexer.Lex(s) 224 if err != nil { 225 t.Fatal(err) 226 } 227 tokens, err := lexer.ConsumeAll(lex) 228 if err != nil { 229 t.Fatal(err) 230 } 231 // for i, t := range tokens { 232 // fmt.Printf("%d: %#v\n", i, t) 233 // } 234 if len(tokens) != 7 { 235 t.Fatalf("Expected 7 got %d", len(tokens)) 236 } 237 } 238 239 func TestSelectWhere(t *testing.T) { 240 p := participle.MustBuild( 241 &Select{}, 242 participle.Lexer(sqlLexer), 243 participle.CaseInsensitive("Keyword"), 244 ) 245 246 s := Select{} 247 cases := []string{ 248 "select * from s3object", 249 "select a, b from s3object s", 250 "select a, b from s3object as s", 251 "select a, b from s3object as s where a = 1", 252 "select a, b from s3object s where a = 1", 253 "select a, b from s3object where a = 1", 254 } 255 for i, tc := range cases { 256 err := p.ParseString(tc, &s) 257 if err != nil { 258 t.Fatalf("%d: %v", i, err) 259 } 260 261 // repr.Println(s, repr.Indent(" "), repr.OmitEmpty(true)) 262 } 263 } 264 265 func TestLikeClause(t *testing.T) { 266 p := participle.MustBuild( 267 &Select{}, 268 participle.Lexer(sqlLexer), 269 participle.CaseInsensitive("Keyword"), 270 ) 271 272 s := Select{} 273 cases := []string{ 274 `select * from s3object where Name like 'abcd'`, 275 `select Name like 'abc' from s3object`, 276 `select * from s3object where Name not like 'abc'`, 277 `select * from s3object where Name like 'abc' escape 't'`, 278 `select * from s3object where Name like 'a\%' escape '?'`, 279 `select * from s3object where Name not like 'abc\' escape '?'`, 280 `select * from s3object where Name like 'a\%' escape LOWER('?')`, 281 `select * from s3object where Name not like LOWER('Bc\') escape '?'`, 282 } 283 for i, tc := range cases { 284 err := p.ParseString(tc, &s) 285 if err != nil { 286 t.Errorf("%d: %v", i, err) 287 } 288 } 289 } 290 291 func TestBetweenClause(t *testing.T) { 292 p := participle.MustBuild( 293 &Select{}, 294 participle.Lexer(sqlLexer), 295 participle.CaseInsensitive("Keyword"), 296 ) 297 298 s := Select{} 299 cases := []string{ 300 `select * from s3object where Id between 1 and 2`, 301 `select * from s3object where Id between 1 and 2 and name = 'Ab'`, 302 `select * from s3object where Id not between 1 and 2`, 303 `select * from s3object where Id not between 1 and 2 and name = 'Bc'`, 304 } 305 for i, tc := range cases { 306 err := p.ParseString(tc, &s) 307 if err != nil { 308 t.Errorf("%d: %v", i, err) 309 } 310 } 311 } 312 313 func TestFromClauseJSONPath(t *testing.T) { 314 p := participle.MustBuild( 315 &Select{}, 316 participle.Lexer(sqlLexer), 317 participle.CaseInsensitive("Keyword"), 318 ) 319 320 s := Select{} 321 cases := []string{ 322 "select * from s3object", 323 "select * from s3object[*].name", 324 "select * from s3object[*].books[*]", 325 "select * from s3object[*].books[*].name", 326 "select * from s3object where name > 2", 327 "select * from s3object[*].name where name > 2", 328 "select * from s3object[*].books[*] where name > 2", 329 "select * from s3object[*].books[*].name where name > 2", 330 "select * from s3object[*].books[*] s", 331 "select * from s3object[*].books[*].name as s", 332 "select * from s3object s where name > 2", 333 "select * from s3object[*].name as s where name > 2", 334 } 335 for i, tc := range cases { 336 err := p.ParseString(tc, &s) 337 if err != nil { 338 t.Fatalf("%d: %v", i, err) 339 } 340 341 // repr.Println(s, repr.Indent(" "), repr.OmitEmpty(true)) 342 } 343 344 } 345 346 func TestSelectParsing(t *testing.T) { 347 p := participle.MustBuild( 348 &Select{}, 349 participle.Lexer(sqlLexer), 350 participle.CaseInsensitive("Keyword"), 351 ) 352 353 s := Select{} 354 cases := []string{ 355 "select * from s3object where name > 2 or value > 1 or word > 2", 356 "select s.word.id + 2 from s3object s", 357 "select 1-2-3 from s3object s limit 1", 358 } 359 for i, tc := range cases { 360 err := p.ParseString(tc, &s) 361 if err != nil { 362 t.Fatalf("%d: %v", i, err) 363 } 364 365 // repr.Println(s, repr.Indent(" "), repr.OmitEmpty(true)) 366 } 367 } 368 369 func TestSqlLexerArithOps(t *testing.T) { 370 s := bytes.NewBuffer([]byte("year from select month hour distinct")) 371 lex, err := sqlLexer.Lex(s) 372 if err != nil { 373 t.Fatal(err) 374 } 375 tokens, err := lexer.ConsumeAll(lex) 376 if err != nil { 377 t.Fatal(err) 378 } 379 if len(tokens) != 7 { 380 t.Errorf("Expected 7 got %d", len(tokens)) 381 } 382 // for i, t := range tokens { 383 // fmt.Printf("%d: %#v\n", i, t) 384 // } 385 }