Ensure NULL/VOID/EMPTY values are compared correctly
This commit is contained in:
parent
327bdd05cd
commit
d367726709
2 changed files with 207 additions and 61 deletions
170
db/fetch.go
170
db/fetch.go
|
@ -409,94 +409,150 @@ func binaryMath(op sql.Token, l, r interface{}) interface{} {
|
||||||
|
|
||||||
func binaryCheck(op sql.Token, l, r, lo, ro interface{}, d *data.Doc) interface{} {
|
func binaryCheck(op sql.Token, l, r, lo, ro interface{}, d *data.Doc) interface{} {
|
||||||
|
|
||||||
|
switch lo.(type) {
|
||||||
|
case *sql.Void:
|
||||||
|
switch ro.(type) {
|
||||||
|
default:
|
||||||
|
return op == sql.NEQ
|
||||||
|
case nil:
|
||||||
|
return op == sql.NEQ
|
||||||
|
case *sql.Void:
|
||||||
|
return op == sql.EQ
|
||||||
|
case *sql.Empty:
|
||||||
|
return op == sql.EQ
|
||||||
|
case *sql.Ident:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case *sql.Empty:
|
||||||
|
switch ro.(type) {
|
||||||
|
default:
|
||||||
|
return op == sql.NEQ
|
||||||
|
case nil:
|
||||||
|
return op == sql.EQ
|
||||||
|
case *sql.Void:
|
||||||
|
return op == sql.EQ
|
||||||
|
case *sql.Empty:
|
||||||
|
return op == sql.EQ
|
||||||
|
case *sql.Param:
|
||||||
|
break
|
||||||
|
case *sql.Ident:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ro.(type) {
|
||||||
|
case *sql.Void:
|
||||||
|
switch lo.(type) {
|
||||||
|
default:
|
||||||
|
return op == sql.NEQ
|
||||||
|
case nil:
|
||||||
|
return op == sql.NEQ
|
||||||
|
case *sql.Void:
|
||||||
|
return op == sql.EQ
|
||||||
|
case *sql.Empty:
|
||||||
|
return op == sql.EQ
|
||||||
|
case *sql.Ident:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case *sql.Empty:
|
||||||
|
switch lo.(type) {
|
||||||
|
default:
|
||||||
|
return op == sql.NEQ
|
||||||
|
case nil:
|
||||||
|
return op == sql.EQ
|
||||||
|
case *sql.Void:
|
||||||
|
return op == sql.EQ
|
||||||
|
case *sql.Empty:
|
||||||
|
return op == sql.EQ
|
||||||
|
case *sql.Param:
|
||||||
|
break
|
||||||
|
case *sql.Ident:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if d != nil {
|
if d != nil {
|
||||||
|
|
||||||
switch l := lo.(type) {
|
switch lo.(type) {
|
||||||
|
|
||||||
case *sql.Void:
|
case *sql.Void:
|
||||||
|
|
||||||
switch r.(type) {
|
|
||||||
case nil:
|
|
||||||
return op == sql.NEQ
|
|
||||||
}
|
|
||||||
|
|
||||||
case *sql.Ident:
|
|
||||||
|
|
||||||
switch r.(type) {
|
|
||||||
|
|
||||||
case *sql.Void:
|
|
||||||
if op == sql.EQ {
|
|
||||||
return d.Exists(l.ID) == false
|
|
||||||
} else if op == sql.NEQ {
|
|
||||||
return d.Exists(l.ID) == true
|
|
||||||
}
|
|
||||||
|
|
||||||
case nil:
|
|
||||||
if op == sql.EQ {
|
|
||||||
return d.Exists(l.ID) == true && d.Get(l.ID).Data() == nil
|
|
||||||
} else if op == sql.NEQ {
|
|
||||||
return d.Exists(l.ID) == false || d.Get(l.ID).Data() != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
case *sql.Empty:
|
|
||||||
if op == sql.EQ {
|
|
||||||
return d.Exists(l.ID) == false || d.Get(l.ID).Data() == nil
|
|
||||||
} else if op == sql.NEQ {
|
|
||||||
return d.Exists(l.ID) == true && d.Get(l.ID).Data() != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
switch r := ro.(type) {
|
switch r := ro.(type) {
|
||||||
|
|
||||||
case *sql.Void:
|
|
||||||
|
|
||||||
switch l.(type) {
|
|
||||||
case nil:
|
|
||||||
return op == sql.NEQ
|
|
||||||
}
|
|
||||||
|
|
||||||
case *sql.Ident:
|
case *sql.Ident:
|
||||||
|
|
||||||
switch l.(type) {
|
|
||||||
|
|
||||||
case *sql.Void:
|
|
||||||
if op == sql.EQ {
|
if op == sql.EQ {
|
||||||
return d.Exists(r.ID) == false
|
return d.Exists(r.ID) == false
|
||||||
} else if op == sql.NEQ {
|
} else if op == sql.NEQ {
|
||||||
return d.Exists(r.ID) == true
|
return d.Exists(r.ID) == true
|
||||||
}
|
}
|
||||||
|
|
||||||
case nil:
|
|
||||||
if op == sql.EQ {
|
|
||||||
return d.Exists(r.ID) == true && d.Get(r.ID).Data() == nil
|
|
||||||
} else if op == sql.NEQ {
|
|
||||||
return d.Exists(r.ID) == false || d.Get(r.ID).Data() != nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case *sql.Empty:
|
case *sql.Empty:
|
||||||
|
switch r := ro.(type) {
|
||||||
|
case *sql.Ident:
|
||||||
if op == sql.EQ {
|
if op == sql.EQ {
|
||||||
return d.Exists(r.ID) == false || d.Get(r.ID).Data() == nil
|
return d.Exists(r.ID) == false || d.Get(r.ID).Data() == nil
|
||||||
} else if op == sql.NEQ {
|
} else if op == sql.NEQ {
|
||||||
return d.Exists(r.ID) == true && d.Get(r.ID).Data() != nil
|
return d.Exists(r.ID) == true && d.Get(r.ID).Data() != nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
case nil:
|
||||||
|
switch r := ro.(type) {
|
||||||
|
case *sql.Ident:
|
||||||
|
if op == sql.EQ {
|
||||||
|
return d.Exists(r.ID) == true && d.Get(r.ID).Data() == nil
|
||||||
|
} else if op == sql.NEQ {
|
||||||
|
return d.Exists(r.ID) == false || d.Get(r.ID).Data() != nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch ro.(type) {
|
||||||
|
case *sql.Void:
|
||||||
|
switch l := lo.(type) {
|
||||||
|
case *sql.Ident:
|
||||||
|
if op == sql.EQ {
|
||||||
|
return d.Exists(l.ID) == false
|
||||||
|
} else if op == sql.NEQ {
|
||||||
|
return d.Exists(l.ID) == true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case *sql.Empty:
|
||||||
|
switch l := lo.(type) {
|
||||||
|
case *sql.Ident:
|
||||||
|
if op == sql.EQ {
|
||||||
|
return d.Exists(l.ID) == false || d.Get(l.ID).Data() == nil
|
||||||
|
} else if op == sql.NEQ {
|
||||||
|
return d.Exists(l.ID) == true && d.Get(l.ID).Data() != nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case nil:
|
||||||
|
switch l := lo.(type) {
|
||||||
|
case *sql.Ident:
|
||||||
|
if op == sql.EQ {
|
||||||
|
return d.Exists(l.ID) == true && d.Get(l.ID).Data() == nil
|
||||||
|
} else if op == sql.NEQ {
|
||||||
|
return d.Exists(l.ID) == false || d.Get(l.ID).Data() != nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch l := l.(type) {
|
switch l := l.(type) {
|
||||||
|
|
||||||
|
case *sql.Empty:
|
||||||
|
switch r.(type) {
|
||||||
|
default:
|
||||||
|
return op == sql.NEQ || op == sql.SNI || op == sql.NIS || op == sql.CONTAINSNONE
|
||||||
|
case nil:
|
||||||
|
return op == sql.EQ
|
||||||
|
}
|
||||||
|
|
||||||
case nil:
|
case nil:
|
||||||
switch r := r.(type) {
|
switch r := r.(type) {
|
||||||
default:
|
default:
|
||||||
return op == sql.NEQ || op == sql.SNI || op == sql.NIS || op == sql.CONTAINSNONE
|
return op == sql.NEQ || op == sql.SNI || op == sql.NIS || op == sql.CONTAINSNONE
|
||||||
case nil:
|
case nil:
|
||||||
return op == sql.EQ
|
return op == sql.EQ
|
||||||
|
case *sql.Empty:
|
||||||
|
return op == sql.EQ
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
return chkArrayR(op, l, r)
|
return chkArrayR(op, l, r)
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
|
|
|
@ -24,6 +24,96 @@ import (
|
||||||
|
|
||||||
func TestSelect(t *testing.T) {
|
func TestSelect(t *testing.T) {
|
||||||
|
|
||||||
|
Convey("Select temps", t, func() {
|
||||||
|
|
||||||
|
setupDB()
|
||||||
|
|
||||||
|
txt := `
|
||||||
|
|
||||||
|
USE NS test DB test;
|
||||||
|
|
||||||
|
LET var = NULL;
|
||||||
|
|
||||||
|
SELECT * FROM "test" WHERE NULL = "";
|
||||||
|
SELECT * FROM "test" WHERE NULL = $var;
|
||||||
|
SELECT * FROM "test" WHERE NULL = VOID;
|
||||||
|
SELECT * FROM "test" WHERE NULL = NULL;
|
||||||
|
SELECT * FROM "test" WHERE NULL = EMPTY;
|
||||||
|
|
||||||
|
SELECT * FROM "test" WHERE "" = NULL;
|
||||||
|
SELECT * FROM "test" WHERE $var = NULL;
|
||||||
|
SELECT * FROM "test" WHERE VOID = NULL;
|
||||||
|
SELECT * FROM "test" WHERE NULL = NULL;
|
||||||
|
SELECT * FROM "test" WHERE EMPTY = NULL;
|
||||||
|
|
||||||
|
SELECT * FROM "test" WHERE VOID = "";
|
||||||
|
SELECT * FROM "test" WHERE VOID = $var;
|
||||||
|
SELECT * FROM "test" WHERE VOID = NULL;
|
||||||
|
SELECT * FROM "test" WHERE VOID = VOID;
|
||||||
|
SELECT * FROM "test" WHERE VOID = EMPTY;
|
||||||
|
|
||||||
|
SELECT * FROM "test" WHERE "" = VOID;
|
||||||
|
SELECT * FROM "test" WHERE $var = VOID;
|
||||||
|
SELECT * FROM "test" WHERE NULL = VOID;
|
||||||
|
SELECT * FROM "test" WHERE VOID = VOID;
|
||||||
|
SELECT * FROM "test" WHERE EMPTY = VOID;
|
||||||
|
|
||||||
|
SELECT * FROM "test" WHERE EMPTY = "";
|
||||||
|
SELECT * FROM "test" WHERE EMPTY = $var;
|
||||||
|
SELECT * FROM "test" WHERE EMPTY = NULL;
|
||||||
|
SELECT * FROM "test" WHERE EMPTY = VOID;
|
||||||
|
SELECT * FROM "test" WHERE EMPTY = EMPTY;
|
||||||
|
|
||||||
|
SELECT * FROM "test" WHERE "" = EMPTY;
|
||||||
|
SELECT * FROM "test" WHERE $var = EMPTY;
|
||||||
|
SELECT * FROM "test" WHERE NULL = EMPTY;
|
||||||
|
SELECT * FROM "test" WHERE VOID = EMPTY;
|
||||||
|
SELECT * FROM "test" WHERE EMPTY = EMPTY;
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
res, err := Execute(setupKV(), txt, nil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(res, ShouldHaveLength, 32)
|
||||||
|
|
||||||
|
So(res[2].Result, ShouldHaveLength, 0)
|
||||||
|
So(res[3].Result, ShouldHaveLength, 1)
|
||||||
|
So(res[4].Result, ShouldHaveLength, 0)
|
||||||
|
So(res[5].Result, ShouldHaveLength, 1)
|
||||||
|
So(res[6].Result, ShouldHaveLength, 1)
|
||||||
|
|
||||||
|
So(res[7].Result, ShouldHaveLength, 0)
|
||||||
|
So(res[8].Result, ShouldHaveLength, 1)
|
||||||
|
So(res[9].Result, ShouldHaveLength, 0)
|
||||||
|
So(res[10].Result, ShouldHaveLength, 1)
|
||||||
|
So(res[11].Result, ShouldHaveLength, 1)
|
||||||
|
|
||||||
|
So(res[12].Result, ShouldHaveLength, 0)
|
||||||
|
So(res[13].Result, ShouldHaveLength, 0)
|
||||||
|
So(res[14].Result, ShouldHaveLength, 0)
|
||||||
|
So(res[15].Result, ShouldHaveLength, 1)
|
||||||
|
So(res[16].Result, ShouldHaveLength, 1)
|
||||||
|
|
||||||
|
So(res[17].Result, ShouldHaveLength, 0)
|
||||||
|
So(res[18].Result, ShouldHaveLength, 0)
|
||||||
|
So(res[19].Result, ShouldHaveLength, 0)
|
||||||
|
So(res[20].Result, ShouldHaveLength, 1)
|
||||||
|
So(res[21].Result, ShouldHaveLength, 1)
|
||||||
|
|
||||||
|
So(res[22].Result, ShouldHaveLength, 0)
|
||||||
|
So(res[23].Result, ShouldHaveLength, 1)
|
||||||
|
So(res[24].Result, ShouldHaveLength, 1)
|
||||||
|
So(res[25].Result, ShouldHaveLength, 1)
|
||||||
|
So(res[26].Result, ShouldHaveLength, 1)
|
||||||
|
|
||||||
|
So(res[27].Result, ShouldHaveLength, 0)
|
||||||
|
So(res[28].Result, ShouldHaveLength, 1)
|
||||||
|
So(res[29].Result, ShouldHaveLength, 1)
|
||||||
|
So(res[30].Result, ShouldHaveLength, 1)
|
||||||
|
So(res[31].Result, ShouldHaveLength, 1)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
Convey("Select records from one thing", t, func() {
|
Convey("Select records from one thing", t, func() {
|
||||||
|
|
||||||
setupDB()
|
setupDB()
|
||||||
|
|
Loading…
Reference in a new issue