Commit f39e59d4 authored by Michael Eisendle's avatar Michael Eisendle Committed by GitHub

Support lt,gt,le,ge,ne,eq operators for blob (#180)

Support blob type for lt,gt,le,ge,ne,eq operators using native bytes.Compare
parent a41c7060
......@@ -10,6 +10,7 @@ Boy van Duuren <boy@vanduuren.xyz>
Dan Kortschak <dan.kortschak@adelaide.edu.au>
Geofrey Ernest <geofreyernest@live.com>
Jan Mercl <0xjnml@gmail.com>
Michael Eisendle <michael@eisendle.me>
OpenNota <opennota@gmail.com>
Victor Kryukov <victor.kryukov@gmail.com>
Viktor Kojouharov <vkojouharov@gmail.com>
......@@ -3722,3 +3722,77 @@ func TestSleep(t *testing.T) {
}
}
}
func testBlobSize(t *testing.T, size int) {
db, err := sql.Open("ql-mem", "")
if err != nil {
t.Fatal(err)
}
defer db.Close()
tx, err := db.Begin()
if err != nil {
t.Fatal(err)
}
// create a table with the blob we want to compare
a := bytes.Repeat([]byte{'A'}, size)
b := bytes.Repeat([]byte{'B'}, size)
tableName := fmt.Sprintf("b%d", size)
_, err = tx.Exec(strings.Replace(`
BEGIN TRANSACTION;
CREATE TABLE tbl (a blob, b blob);
INSERT INTO tbl VALUES ($1, $2);
COMMIT;`, "tbl", tableName, -1), a, b)
if err != nil {
t.Fatal(err)
}
if err := tx.Commit(); err != nil {
t.Fatal(err)
}
// the operators we want to test, one if true, zero if false
stmts := `select count(*) from tbl where a = b;
select count(*) from tbl where a < b;
select count(*) from tbl where a > b;
select count(*) from tbl where a <= b;
select count(*) from tbl where a >= b;
select count(*) from tbl where a != b;`
stmts = strings.Replace(stmts, "tbl", tableName, -1)
var expected = []int{0, 1, 0, 1, 0, 1}
var result []int
// execute statements one by one and append the result
for _, q := range strings.Split(stmts, "\n") {
rows, err := db.Query(q)
if err != nil {
t.Fatal(err)
}
for rows.Next() {
var rv int
err = rows.Scan(&rv)
if err != nil {
t.Error(err)
}
result = append(result, rv)
}
}
// compare the result to what we expected
if reflect.DeepEqual(result, expected) == false {
t.Errorf("expected: %v, result: %v", expected, result)
}
}
func TestBlobCompare(t *testing.T) {
RegisterMemDriver()
// check the operators for the given sizes
sizes := []int{4, 128, 1024, 16384}
for _, size := range sizes {
testBlobSize(t, size)
}
}
......@@ -1089,7 +1089,7 @@
//
// - Rational values are comparable and ordered, in the usual way.
//
// - String values are comparable and ordered, lexically byte-wise.
// - String and Blob values are comparable and ordered, lexically byte-wise.
//
// - Time values are comparable and ordered.
//
......
......@@ -5,6 +5,7 @@
package ql
import (
"bytes"
"fmt"
"math/big"
"regexp"
......@@ -779,6 +780,13 @@ func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}
default:
return invOp2(x, y, op)
}
case []byte:
switch y := b.(type) {
case []byte:
return bytes.Compare(x, y) == 0, nil
default:
return invOp2(x, y, op)
}
default:
return invOp2(a, b, op)
}
......@@ -930,6 +938,13 @@ func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}
default:
return invOp2(x, y, op)
}
case []byte:
switch y := b.(type) {
case []byte:
return bytes.Compare(x, y) < 0, nil
default:
return invOp2(x, y, op)
}
default:
return invOp2(a, b, op)
}
......@@ -1081,6 +1096,13 @@ func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}
default:
return invOp2(x, y, op)
}
case []byte:
switch y := b.(type) {
case []byte:
return bytes.Compare(x, y) <= 0, nil
default:
return invOp2(x, y, op)
}
default:
return invOp2(a, b, op)
}
......@@ -1232,6 +1254,13 @@ func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}
default:
return invOp2(x, y, op)
}
case []byte:
switch y := b.(type) {
case []byte:
return bytes.Compare(x, y) >= 0, nil
default:
return invOp2(x, y, op)
}
default:
return invOp2(a, b, op)
}
......@@ -1403,6 +1432,13 @@ func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}
default:
return invOp2(x, y, op)
}
case []byte:
switch y := b.(type) {
case []byte:
return bytes.Compare(x, y) != 0, nil
default:
return invOp2(x, y, op)
}
default:
return invOp2(a, b, op)
}
......@@ -1574,6 +1610,13 @@ func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}
default:
return invOp2(x, y, op)
}
case []byte:
switch y := b.(type) {
case []byte:
return bytes.Compare(x, y) == 0, nil
default:
return invOp2(x, y, op)
}
default:
return invOp2(a, b, op)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment