mirror of https://github.com/mattn/go-sqlite3.git
Merge pull request #454 from gholt/master
Fix to better handle NULL values in TEXT and BLOB columns.
This commit is contained in:
commit
144deb6596
|
@ -867,10 +867,11 @@ func (s *SQLiteStmt) bind(args []namedValue) error {
|
||||||
case float64:
|
case float64:
|
||||||
rv = C.sqlite3_bind_double(s.s, n, C.double(v))
|
rv = C.sqlite3_bind_double(s.s, n, C.double(v))
|
||||||
case []byte:
|
case []byte:
|
||||||
if len(v) == 0 {
|
ln := len(v)
|
||||||
|
if ln == 0 {
|
||||||
v = placeHolder
|
v = placeHolder
|
||||||
}
|
}
|
||||||
rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(&v[0]), C.int(len(v)))
|
rv = C._sqlite3_bind_blob(s.s, n, unsafe.Pointer(&v[0]), C.int(ln))
|
||||||
case time.Time:
|
case time.Time:
|
||||||
b := []byte(v.Format(SQLiteTimestampFormats[0]))
|
b := []byte(v.Format(SQLiteTimestampFormats[0]))
|
||||||
rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b)))
|
rv = C._sqlite3_bind_text(s.s, n, (*C.char)(unsafe.Pointer(&b[0])), C.int(len(b)))
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package sqlite3
|
package sqlite3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -1343,6 +1344,61 @@ func TestUpdateAndTransactionHooks(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNilAndEmptyBytes(t *testing.T) {
|
||||||
|
db, err := sql.Open("sqlite3", ":memory:")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
actualNil := []byte("use this to use an actual nil not a reference to nil")
|
||||||
|
emptyBytes := []byte{}
|
||||||
|
for tsti, tst := range []struct {
|
||||||
|
name string
|
||||||
|
columnType string
|
||||||
|
insertBytes []byte
|
||||||
|
expectedBytes []byte
|
||||||
|
}{
|
||||||
|
{"actual nil blob", "blob", actualNil, nil},
|
||||||
|
{"referenced nil blob", "blob", nil, nil},
|
||||||
|
{"empty blob", "blob", emptyBytes, emptyBytes},
|
||||||
|
{"actual nil text", "text", actualNil, nil},
|
||||||
|
{"referenced nil text", "text", nil, nil},
|
||||||
|
{"empty text", "text", emptyBytes, emptyBytes},
|
||||||
|
} {
|
||||||
|
if _, err = db.Exec(fmt.Sprintf("create table tbl%d (txt %s)", tsti, tst.columnType)); err != nil {
|
||||||
|
t.Fatal(tst.name, err)
|
||||||
|
}
|
||||||
|
if bytes.Equal(tst.insertBytes, actualNil) {
|
||||||
|
if _, err = db.Exec(fmt.Sprintf("insert into tbl%d (txt) values (?)", tsti), nil); err != nil {
|
||||||
|
t.Fatal(tst.name, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err = db.Exec(fmt.Sprintf("insert into tbl%d (txt) values (?)", tsti), &tst.insertBytes); err != nil {
|
||||||
|
t.Fatal(tst.name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rows, err := db.Query(fmt.Sprintf("select txt from tbl%d", tsti))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(tst.name, err)
|
||||||
|
}
|
||||||
|
if !rows.Next() {
|
||||||
|
t.Fatal(tst.name, "no rows")
|
||||||
|
}
|
||||||
|
var scanBytes []byte
|
||||||
|
if err = rows.Scan(&scanBytes); err != nil {
|
||||||
|
t.Fatal(tst.name, err)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
t.Fatal(tst.name, err)
|
||||||
|
}
|
||||||
|
if tst.expectedBytes == nil && scanBytes != nil {
|
||||||
|
t.Errorf("%s: %#v != %#v", tst.name, scanBytes, tst.expectedBytes)
|
||||||
|
} else if !bytes.Equal(scanBytes, tst.expectedBytes) {
|
||||||
|
t.Errorf("%s: %#v != %#v", tst.name, scanBytes, tst.expectedBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var customFunctionOnce sync.Once
|
var customFunctionOnce sync.Once
|
||||||
|
|
||||||
func BenchmarkCustomFunctions(b *testing.B) {
|
func BenchmarkCustomFunctions(b *testing.B) {
|
||||||
|
|
Loading…
Reference in New Issue