From b6b081b7041ae4a1af79bef096e8c7eb2e4b4afc Mon Sep 17 00:00:00 2001 From: letusfly85 Date: Wed, 10 Feb 2016 16:21:07 +0900 Subject: [PATCH 1/2] add sample code --- main.go | 21 +++++++++++++++++++++ parser.go | 2 +- parser_test.go | 2 +- scanner.go | 2 +- scanner_test.go | 2 +- token.go | 2 +- 6 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 main.go diff --git a/main.go b/main.go new file mode 100644 index 0000000..ea18a7d --- /dev/null +++ b/main.go @@ -0,0 +1,21 @@ +package main + +import "strings" + +func main() { + query := "select * from my_table" + println(query) + r := strings.NewReader(query) + + parser := NewParser(r) + + stmt, err := parser.Parse() + if err != nil { + println(err.Error()) + } + + println(stmt.TableName) + for _, field := range stmt.Fields { + println(field) + } +} diff --git a/parser.go b/parser.go index e68a052..aebd7bf 100644 --- a/parser.go +++ b/parser.go @@ -1,4 +1,4 @@ -package sql +package main import ( "fmt" diff --git a/parser_test.go b/parser_test.go index f50c402..cb60f5b 100644 --- a/parser_test.go +++ b/parser_test.go @@ -1,4 +1,4 @@ -package sql_test +package main import ( "reflect" diff --git a/scanner.go b/scanner.go index 53a1f1f..c393de1 100644 --- a/scanner.go +++ b/scanner.go @@ -1,4 +1,4 @@ -package sql +package main import ( "bufio" diff --git a/scanner_test.go b/scanner_test.go index 78cfa49..dedeed7 100644 --- a/scanner_test.go +++ b/scanner_test.go @@ -1,4 +1,4 @@ -package sql_test +package main import ( "strings" diff --git a/token.go b/token.go index c375a69..0253829 100644 --- a/token.go +++ b/token.go @@ -1,4 +1,4 @@ -package sql +package main // Token represents a lexical token. type Token int From 21cfdf9478297a9e1874ce670108bf3f5d556ecf Mon Sep 17 00:00:00 2001 From: letusfly85 Date: Thu, 11 Feb 2016 13:46:46 +0900 Subject: [PATCH 2/2] add simple pattern --- main.go | 5 ++++- parser.go | 32 ++++++++++++++++++++++++++++++-- scanner.go | 17 ++++++++++++++++- token.go | 3 +++ 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/main.go b/main.go index ea18a7d..a39c720 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,7 @@ package main import "strings" func main() { - query := "select * from my_table" + query := "select id, name from employees where department_id = 3 and salary > 10" println(query) r := strings.NewReader(query) @@ -18,4 +18,7 @@ func main() { for _, field := range stmt.Fields { println(field) } + for _, condition := range stmt.Conditions { + println(condition) + } } diff --git a/parser.go b/parser.go index aebd7bf..0b2dd13 100644 --- a/parser.go +++ b/parser.go @@ -7,8 +7,9 @@ import ( // SelectStatement represents a SQL SELECT statement. type SelectStatement struct { - Fields []string - TableName string + Fields []string + TableName string + Conditions []string } // Parser represents a parser. @@ -63,6 +64,33 @@ func (p *Parser) Parse() (*SelectStatement, error) { } stmt.TableName = lit + // Next we should see the "WHERE" keyword. + if tok, lit := p.scanIgnoreWhitespace(); tok != WHERE { + return nil, fmt.Errorf("found %q, expected WHERE", lit) + } + + // Next we should loop over all our and delimited conditions. + condition := "" + for { + // Read a field. + _, lit := p.scanIgnoreWhitespace() + condition += lit + + if tok, lit := p.scanIgnoreWhitespace(); tok == AND { + stmt.Conditions = append(stmt.Conditions, condition) + condition = "" + } else { + if tok == EOF { + stmt.Conditions = append(stmt.Conditions, condition) + p.unscan() + break + } else { + condition += lit + } + + } + } + // Return the successfully parsed statement. return stmt, nil } diff --git a/scanner.go b/scanner.go index c393de1..203d372 100644 --- a/scanner.go +++ b/scanner.go @@ -35,6 +35,12 @@ func (s *Scanner) Scan() (tok Token, lit string) { // Otherwise read the individual character. switch ch { + case '=': + return OPER, string(ch) + case '>': + return OPER, string(ch) + case '<': + return OPER, string(ch) case eof: return EOF, "" case '*': @@ -93,6 +99,10 @@ func (s *Scanner) scanIdent() (tok Token, lit string) { return SELECT, buf.String() case "FROM": return FROM, buf.String() + case "WHERE": + return WHERE, buf.String() + case "AND": + return AND, buf.String() } // Otherwise return as a regular identifier. @@ -116,10 +126,15 @@ func (s *Scanner) unread() { _ = s.r.UnreadRune() } func isWhitespace(ch rune) bool { return ch == ' ' || ch == '\t' || ch == '\n' } // isLetter returns true if the rune is a letter. -func isLetter(ch rune) bool { return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') } +func isLetter(ch rune) bool { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') //|| isOpers(ch) +} // isDigit returns true if the rune is a digit. func isDigit(ch rune) bool { return (ch >= '0' && ch <= '9') } +// isOpers returns true if the rune is a digit. +func isOpers(ch rune) bool { return ch == '=' || ch == '>' || ch == '<' } + // eof represents a marker rune for the end of the reader. var eof = rune(0) diff --git a/token.go b/token.go index 0253829..ea05133 100644 --- a/token.go +++ b/token.go @@ -19,4 +19,7 @@ const ( // Keywords SELECT FROM + WHERE + AND // and + OPER )