Ensure NULL/VOID/EMPTY values are compared correctly

This commit is contained in:
Tobie Morgan Hitchcock 2017-12-03 00:48:50 +00:00
parent 327bdd05cd
commit d367726709
2 changed files with 207 additions and 61 deletions

View file

@ -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 := ro.(type) {
switch r.(type) { case *sql.Ident:
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) {
case *sql.Void:
switch l.(type) {
case nil:
return op == sql.NEQ
}
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: case *sql.Empty:
if op == sql.EQ { switch r := ro.(type) {
return d.Exists(r.ID) == true && d.Get(r.ID).Data() == nil case *sql.Ident:
} else if op == sql.NEQ {
return d.Exists(r.ID) == false || d.Get(r.ID).Data() != nil
}
case *sql.Empty:
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{}:

View file

@ -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()