blob: cf97db89d8ceef8f458446823d7256acb7481841 [file]
//go:build cgo
package sqlite3
import (
"context"
"database/sql/driver"
"io"
"reflect"
"testing"
)
func TestRowsStepValues(t *testing.T) {
for _, cancellable := range []bool{false, true} {
name := "background"
if cancellable {
name = "cancellable"
}
t.Run(name, func(t *testing.T) {
conn := openContextTestConn(t)
ctx := context.Background()
if cancellable {
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
defer cancel()
}
stmt, err := conn.PrepareContext(ctx, `SELECT 'first', x'0102', 1, 1.5 WHERE :include
UNION ALL SELECT x'0304', 'second', NULL, 2
UNION ALL SELECT '', x'', 3.5, NULL`)
if err != nil {
t.Fatal(err)
}
defer stmt.Close()
want := [][]driver.Value{
{"first", []byte{1, 2}, int64(1), float64(1.5)},
{[]byte{3, 4}, "second", nil, int64(2)},
{"", []byte{}, float64(3.5), nil},
}
// Alternate fused and generic binding with the same buffers.
for run := 0; run < 3; run++ {
args := []driver.NamedValue{{Ordinal: 1, Value: int64(1)}}
if run == 1 {
args[0].Name = "include"
}
rows, err := stmt.(driver.StmtQueryContext).QueryContext(ctx, args)
if err != nil {
t.Fatal(err)
}
var got [][]driver.Value
for range want {
values := make([]driver.Value, 4)
if err := rows.Next(values); err != nil {
t.Fatal(err)
}
got = append(got, values)
}
if err := rows.Next(make([]driver.Value, 4)); err != io.EOF {
t.Fatalf("Next = %v, want EOF", err)
}
if err := rows.Close(); err != nil {
t.Fatal(err)
}
// Retained strings and blobs must survive subsequent steps and reset.
if !reflect.DeepEqual(got, want) {
t.Fatalf("got %#v, want %#v", got, want)
}
}
})
}
}