385 lines · 8.8 KB · Go
RawDownload
// Copyright (c) 2015-2021 MinIO, Inc.//// This file is part of MinIO Object Storage stack//// This program is free software: you can redistribute it and/or modify// it under the terms of the GNU Affero General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU Affero General Public License for more details.//// You should have received a copy of the GNU Affero General Public License// along with this program.  If not, see <http://www.gnu.org/licenses/>. package sql import (	"bytes"	"testing" 	"github.com/alecthomas/participle"	"github.com/alecthomas/participle/lexer") func TestJSONPathElement(t *testing.T) {	p := participle.MustBuild(		&JSONPathElement{},		participle.Lexer(sqlLexer),		participle.CaseInsensitive("Keyword"),		participle.CaseInsensitive("Timeword"),	) 	j := JSONPathElement{}	cases := []string{		// Key		"['name']", ".name", `."name"`, 		// Index		"[2]", "[0]", "[100]", 		// Object wilcard		".*", 		// array wildcard		"[*]",	}	for i, tc := range cases {		err := p.ParseString(tc, &j)		if err != nil {			t.Fatalf("%d: %v", i, err)		}		// repr.Println(j, repr.Indent("  "), repr.OmitEmpty(true))	}} func TestJSONPath(t *testing.T) {	p := participle.MustBuild(		&JSONPath{},		participle.Lexer(sqlLexer),		participle.CaseInsensitive("Keyword"),		participle.CaseInsensitive("Timeword"),	) 	j := JSONPath{}	cases := []string{		"S3Object",		"S3Object.id",		"S3Object.book.title",		"S3Object.id[1]",		"S3Object.id['abc']",		"S3Object.id['ab']",		"S3Object.words.*.id",		"S3Object.words.name[*].val",		"S3Object.words.name[*].val[*]",		"S3Object.words.name[*].val.*",	}	for i, tc := range cases {		err := p.ParseString(tc, &j)		if err != nil {			t.Fatalf("%d: %v", i, err)		}		// repr.Println(j, repr.Indent("  "), repr.OmitEmpty(true))	}} func TestIdentifierParsing(t *testing.T) {	p := participle.MustBuild(		&Identifier{},		participle.Lexer(sqlLexer),		participle.CaseInsensitive("Keyword"),	) 	id := Identifier{}	validCases := []string{		"a",		"_a",		"abc_a",		"a2",		`"abc"`,		`"abc\a""ac"`,	}	for i, tc := range validCases {		err := p.ParseString(tc, &id)		if err != nil {			t.Fatalf("%d: %v", i, err)		}		// repr.Println(id, repr.Indent("  "), repr.OmitEmpty(true))	} 	invalidCases := []string{		"+a",		"-a",		"1a",		`"ab`,		`abc"`,		`aa""a`,		`"a"a"`,	}	for i, tc := range invalidCases {		err := p.ParseString(tc, &id)		if err == nil {			t.Fatalf("%d: %v", i, err)		}		// fmt.Println(tc, err)	}} func TestLiteralStringParsing(t *testing.T) {	var k ObjectKey	p := participle.MustBuild(		&ObjectKey{},		participle.Lexer(sqlLexer),		participle.CaseInsensitive("Keyword"),	) 	validCases := []string{		"['abc']",		"['ab''c']",		"['a''b''c']",		"['abc-x_1##@(*&(#*))/\\']",	}	for i, tc := range validCases {		err := p.ParseString(tc, &k)		if err != nil {			t.Fatalf("%d: %v", i, err)		}		if string(*k.Lit) == "" {			t.Fatalf("Incorrect parse %#v", k)		}		// repr.Println(k, repr.Indent("  "), repr.OmitEmpty(true))	} 	invalidCases := []string{		"['abc'']",		"['-abc'sc']",		"[abc']",		"['ac]",	}	for i, tc := range invalidCases {		err := p.ParseString(tc, &k)		if err == nil {			t.Fatalf("%d: %v", i, err)		}		// fmt.Println(tc, err)	}} func TestFunctionParsing(t *testing.T) {	var fex FuncExpr	p := participle.MustBuild(		&FuncExpr{},		participle.Lexer(sqlLexer),		participle.CaseInsensitive("Keyword"),		participle.CaseInsensitive("Timeword"),	) 	validCases := []string{		"count(*)",		"sum(2 + s.id)",		"sum(t)",		"avg(s.id[1])",		"coalesce(s.id[1], 2, 2 + 3)", 		"cast(s as string)",		"cast(s AS INT)",		"cast(s as DECIMAL)",		"extract(YEAR from '2018-01-09')",		"extract(month from '2018-01-09')", 		"extract(hour from '2018-01-09')",		"extract(day from '2018-01-09')",		"substring('abcd' from 2 for 2)",		"substring('abcd' from 2)",		"substring('abcd' , 2 , 2)", 		"substring('abcd' , 22 )",		"trim('  aab  ')",		"trim(leading from '  aab  ')",		"trim(trailing from '  aab  ')",		"trim(both from '  aab  ')", 		"trim(both '12' from '  aab  ')",		"trim(leading '12' from '  aab  ')",		"trim(trailing '12' from '  aab  ')",		"count(23)",	}	for i, tc := range validCases {		err := p.ParseString(tc, &fex)		if err != nil {			t.Fatalf("%d: %v", i, err)		}		// repr.Println(fex, repr.Indent("  "), repr.OmitEmpty(true))	}} func TestSqlLexer(t *testing.T) {	// s := bytes.NewBuffer([]byte("s.['name'].*.[*].abc.[\"abc\"]"))	s := bytes.NewBuffer([]byte("S3Object.words.*.id"))	// s := bytes.NewBuffer([]byte("COUNT(Id)"))	lex, err := sqlLexer.Lex(s)	if err != nil {		t.Fatal(err)	}	tokens, err := lexer.ConsumeAll(lex)	if err != nil {		t.Fatal(err)	}	// for i, t := range tokens {	// 	fmt.Printf("%d: %#v\n", i, t)	// }	if len(tokens) != 7 {		t.Fatalf("Expected 7 got %d", len(tokens))	}} func TestSelectWhere(t *testing.T) {	p := participle.MustBuild(		&Select{},		participle.Lexer(sqlLexer),		participle.CaseInsensitive("Keyword"),	) 	s := Select{}	cases := []string{		"select * from s3object",		"select a, b from s3object s",		"select a, b from s3object as s",		"select a, b from s3object as s where a = 1",		"select a, b from s3object s where a = 1",		"select a, b from s3object where a = 1",	}	for i, tc := range cases {		err := p.ParseString(tc, &s)		if err != nil {			t.Fatalf("%d: %v", i, err)		} 		// repr.Println(s, repr.Indent("  "), repr.OmitEmpty(true))	}} func TestLikeClause(t *testing.T) {	p := participle.MustBuild(		&Select{},		participle.Lexer(sqlLexer),		participle.CaseInsensitive("Keyword"),	) 	s := Select{}	cases := []string{		`select * from s3object where Name like 'abcd'`,		`select Name like 'abc' from s3object`,		`select * from s3object where Name not like 'abc'`,		`select * from s3object where Name like 'abc' escape 't'`,		`select * from s3object where Name like 'a\%' escape '?'`,		`select * from s3object where Name not like 'abc\' escape '?'`,		`select * from s3object where Name like 'a\%' escape LOWER('?')`,		`select * from s3object where Name not like LOWER('Bc\') escape '?'`,	}	for i, tc := range cases {		err := p.ParseString(tc, &s)		if err != nil {			t.Errorf("%d: %v", i, err)		}	}} func TestBetweenClause(t *testing.T) {	p := participle.MustBuild(		&Select{},		participle.Lexer(sqlLexer),		participle.CaseInsensitive("Keyword"),	) 	s := Select{}	cases := []string{		`select * from s3object where Id between 1 and 2`,		`select * from s3object where Id between 1 and 2 and name = 'Ab'`,		`select * from s3object where Id not between 1 and 2`,		`select * from s3object where Id not between 1 and 2 and name = 'Bc'`,	}	for i, tc := range cases {		err := p.ParseString(tc, &s)		if err != nil {			t.Errorf("%d: %v", i, err)		}	}} func TestFromClauseJSONPath(t *testing.T) {	p := participle.MustBuild(		&Select{},		participle.Lexer(sqlLexer),		participle.CaseInsensitive("Keyword"),	) 	s := Select{}	cases := []string{		"select * from s3object",		"select * from s3object[*].name",		"select * from s3object[*].books[*]",		"select * from s3object[*].books[*].name",		"select * from s3object where name > 2",		"select * from s3object[*].name where name > 2",		"select * from s3object[*].books[*] where name > 2",		"select * from s3object[*].books[*].name where name > 2",		"select * from s3object[*].books[*] s",		"select * from s3object[*].books[*].name as s",		"select * from s3object s where name > 2",		"select * from s3object[*].name as s where name > 2",		"select * from s3object[*].books[*] limit 1",	}	for i, tc := range cases {		err := p.ParseString(tc, &s)		if err != nil {			t.Fatalf("%d: %v", i, err)		} 		// repr.Println(s, repr.Indent("  "), repr.OmitEmpty(true))	}} func TestSelectParsing(t *testing.T) {	p := participle.MustBuild(		&Select{},		participle.Lexer(sqlLexer),		participle.CaseInsensitive("Keyword"),	) 	s := Select{}	cases := []string{		"select * from s3object where name > 2 or value > 1 or word > 2",		"select s.word.id + 2 from s3object s",		"select 1-2-3 from s3object s limit 1",	}	for i, tc := range cases {		err := p.ParseString(tc, &s)		if err != nil {			t.Fatalf("%d: %v", i, err)		} 		// repr.Println(s, repr.Indent("  "), repr.OmitEmpty(true))	}} func TestSqlLexerArithOps(t *testing.T) {	s := bytes.NewBuffer([]byte("year from select month hour distinct"))	lex, err := sqlLexer.Lex(s)	if err != nil {		t.Fatal(err)	}	tokens, err := lexer.ConsumeAll(lex)	if err != nil {		t.Fatal(err)	}	if len(tokens) != 7 {		t.Errorf("Expected 7 got %d", len(tokens))	}	// for i, t := range tokens {	// 	fmt.Printf("%d: %#v\n", i, t)	// }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t