Skip to content

Commit

Permalink
feat (engine): handle IS NULL and IS NOT NULL
Browse files Browse the repository at this point in the history
  • Loading branch information
proullon committed Nov 28, 2015
1 parent ae096be commit f60ad5b
Show file tree
Hide file tree
Showing 8 changed files with 275 additions and 61 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -21,4 +21,4 @@ _cgo_export.*
_testmain.go

*.exe
engine/parser/log.go
examples/
54 changes: 0 additions & 54 deletions driver/update_test.go

This file was deleted.

8 changes: 8 additions & 0 deletions engine/operator.go
Expand Up @@ -129,3 +129,11 @@ func inOperator(leftValue Value, rightValue Value) bool {

return false
}

func isNullOperator(leftValue Value, rightValue Value) bool {
return leftValue.v == nil
}

func isNotNullOperator(leftValue Value, rightValue Value) bool {
return leftValue.v != nil
}
32 changes: 31 additions & 1 deletion engine/orderby_test.go
Expand Up @@ -10,7 +10,7 @@ import (
func TestOrderByInt(t *testing.T) {
log.UseTestLogger(t)

db, err := sql.Open("ramsql", "TestOrderBy")
db, err := sql.Open("ramsql", "TestOrderByInt")
if err != nil {
t.Fatalf("sql.Open : Error : %s\n", err)
}
Expand Down Expand Up @@ -39,6 +39,7 @@ func TestOrderByInt(t *testing.T) {
if err != nil {
t.Fatalf("Cannot select and order by age: %s", err)
}
defer rows.Close()

var age, last, size int64
last = 4000
Expand Down Expand Up @@ -202,3 +203,32 @@ func TestOrderByLimit(t *testing.T) {
t.Fatalf("Expecting 2 rows here, got %d", size)
}
}

func TestOrderByIntEmpty(t *testing.T) {
log.UseTestLogger(t)

db, err := sql.Open("ramsql", "TestOrderByIntEmpty")
if err != nil {
t.Fatalf("sql.Open : Error : %s\n", err)
}
defer db.Close()

batch := []string{
`CREATE TABLE user (name TEXT, surname TEXT, age INT);`,
}

for _, b := range batch {
_, err = db.Exec(b)
if err != nil {
t.Fatalf("sql.Exec: Error: %s", err)
}
}

query := `SELECT age FROM user WHERE surname = Wayne OR surname = Doe ORDER BY age DESC`
rows, err := db.Query(query)
if err != nil {
t.Fatalf("Cannot select and order by age: %s", err)
}
defer rows.Close()

}
6 changes: 6 additions & 0 deletions engine/parser/lexer.go
Expand Up @@ -66,6 +66,7 @@ const (
AscToken
DescToken
LimitToken
IsToken

// Type Token

Expand Down Expand Up @@ -150,6 +151,7 @@ func (l *lexer) lex(instruction []byte) ([]Token, error) {
matchers = append(matchers, l.MatchAscToken)
matchers = append(matchers, l.MatchDescToken)
matchers = append(matchers, l.MatchLimitToken)
matchers = append(matchers, l.MatchIsToken)
// Type Matcher
matchers = append(matchers, l.MatchPrimaryToken)
matchers = append(matchers, l.MatchKeyToken)
Expand Down Expand Up @@ -243,6 +245,10 @@ func (l *lexer) MatchZoneToken() bool {
return l.Match([]byte("zone"), ZoneToken)
}

func (l *lexer) MatchIsToken() bool {
return l.Match([]byte("is"), IsToken)
}

func (l *lexer) MatchLimitToken() bool {
return l.Match([]byte("limit"), LimitToken)
}
Expand Down
25 changes: 24 additions & 1 deletion engine/parser/parser.go
Expand Up @@ -447,7 +447,6 @@ func (p *parser) parseAttribute() (*Decl, error) {
return nil, p.syntaxError()
}
decl := NewDecl(p.cur())
log.Debug("Decl is %v", decl)

if quoted {
// Check there is a closing quote
Expand Down Expand Up @@ -546,6 +545,30 @@ func (p *parser) parseCondition() (*Decl, error) {
}
attributeDecl.Add(inDecl)
return attributeDecl, nil
case IsToken:
log.Debug("parseCondition: IsToken\n")
decl, err := p.consumeToken(IsToken)
if err != nil {
return nil, err
}
attributeDecl.Add(decl)
if p.cur().Token == NotToken {
log.Debug("parseCondition: NotToken\n")
notDecl, err := p.consumeToken(NotToken)
if err != nil {
return nil, err
}
decl.Add(notDecl)
}
if p.cur().Token == NullToken {
log.Debug("parseCondition: NullToken\n")
nullDecl, err := p.consumeToken(NullToken)
if err != nil {
return nil, err
}
decl.Add(nullDecl)
}
return attributeDecl, nil
}

// Value
Expand Down
45 changes: 41 additions & 4 deletions engine/select.go
Expand Up @@ -15,7 +15,7 @@ func attributeExistsInTable(e *Engine, attr string, table string) error {

r := e.relation(table)
if r == nil {
return fmt.Errorf("table %s does not exist", table)
return fmt.Errorf("table \"%s\" does not exist", table)
}

found := false
Expand Down Expand Up @@ -269,6 +269,18 @@ func inExecutor(inDecl *parser.Decl, p *Predicate) error {
return nil
}

func isExecutor(isDecl *parser.Decl, p *Predicate) error {
isDecl.Stringy(0)

if isDecl.Decl[0].Token == parser.NullToken {
p.Operator = isNullOperator
} else {
p.Operator = isNotNullOperator
}

return nil
}

func or(e *Engine, left []*parser.Decl, right []*parser.Decl, tableName string) (PredicateLinker, error) {
p := &orOperator{}

Expand Down Expand Up @@ -345,7 +357,7 @@ func whereExecutor2(e *Engine, decl []*parser.Decl, fromTableName string) (Predi
}

switch cond.Decl[0].Token {
case parser.InToken, parser.EqualityToken, parser.LeftDipleToken, parser.RightDipleToken:
case parser.IsToken, parser.InToken, parser.EqualityToken, parser.LeftDipleToken, parser.RightDipleToken:
break
default:
fromTableName = cond.Decl[0].Lexeme
Expand All @@ -369,6 +381,16 @@ func whereExecutor2(e *Engine, decl []*parser.Decl, fromTableName string) (Predi
return p, nil
}

// Handle IS NULL and IS NOT NULL
if cond.Decl[0].Token == parser.IsToken {
err := isExecutor(cond.Decl[0], p)
if err != nil {
return nil, err
}
p.LeftValue.table = fromTableName
return p, nil
}

if len(cond.Decl) < 2 {
return nil, fmt.Errorf("Malformed predicate \"%s\"", cond.Lexeme)
}
Expand Down Expand Up @@ -417,10 +439,14 @@ func whereExecutor(whereDecl *parser.Decl, fromTableName string) ([]Predicate, e

switch cond.Decl[0].Token {
case parser.EqualityToken, parser.LeftDipleToken, parser.RightDipleToken:
log.Debug("whereExecutor: it's = < >")
log.Debug("whereExecutor: it's = < >\n")
break
case parser.InToken:
log.Debug("whereExecutor: it's IN")
log.Debug("whereExecutor: it's IN\n")
break
case parser.IsToken:
log.Debug("whereExecutor: it's IS token\n")
log.Debug("whereExecutor: %+v\n", cond.Decl[0])
break
default:
log.Debug("it's the table name ! -> %s", cond.Decl[0].Lexeme)
Expand All @@ -442,6 +468,17 @@ func whereExecutor(whereDecl *parser.Decl, fromTableName string) ([]Predicate, e
continue
}

// Handle IS NULL and IS NOT NULL
if cond.Decl[0].Token == parser.IsToken {
err := isExecutor(cond.Decl[0], &p)
if err != nil {
return nil, err
}
p.LeftValue.table = tableName
predicates = append(predicates, p)
continue
}

if len(cond.Decl) < 2 {
return nil, fmt.Errorf("Malformed predicate \"%s\"", cond.Lexeme)
}
Expand Down

0 comments on commit f60ad5b

Please sign in to comment.