|  | 
|  | 1 | +// Copyright (c) 2023 Tailscale Inc & AUTHORS All rights reserved. | 
|  | 2 | +// Use of this source code is governed by a BSD-style | 
|  | 3 | +// license that can be found in the LICENSE file. | 
|  | 4 | + | 
|  | 5 | +package sqlite | 
|  | 6 | + | 
|  | 7 | +import ( | 
|  | 8 | +	"context" | 
|  | 9 | +	"math" | 
|  | 10 | +	"reflect" | 
|  | 11 | +	"testing" | 
|  | 12 | + | 
|  | 13 | +	"github.com/google/go-cmp/cmp" | 
|  | 14 | +) | 
|  | 15 | + | 
|  | 16 | +func TestQueryBinary(t *testing.T) { | 
|  | 17 | +	ctx := WithPersist(context.Background()) | 
|  | 18 | +	db := openTestDB(t) | 
|  | 19 | +	exec(t, db, "CREATE TABLE t (id INTEGER PRIMARY KEY, f REAL, txt TEXT, blb BLOB)") | 
|  | 20 | +	exec(t, db, "INSERT INTO t VALUES (?, ?, ?, ?)", math.MinInt64, 1.0, "text-a", "blob-a") | 
|  | 21 | +	exec(t, db, "INSERT INTO t VALUES (?, ?, ?, ?)", -1, -1.0, "text-b", "blob-b") | 
|  | 22 | +	exec(t, db, "INSERT INTO t VALUES (?, ?, ?, ?)", 0, 0, "text-c", "blob-c") | 
|  | 23 | +	exec(t, db, "INSERT INTO t VALUES (?, ?, ?, ?)", 20, 2, "text-d", "blob-d") | 
|  | 24 | +	exec(t, db, "INSERT INTO t VALUES (?, ?, ?, ?)", math.MaxInt64, nil, "text-e", "blob-e") | 
|  | 25 | +	exec(t, db, "INSERT INTO t VALUES (?, ?, ?, ?)", 42, 0.25, "text-f", nil) | 
|  | 26 | +	exec(t, db, "INSERT INTO t VALUES (?, ?, ?, ?)", 43, 1.75, "text-g", nil) | 
|  | 27 | + | 
|  | 28 | +	conn, err := db.Conn(ctx) | 
|  | 29 | +	if err != nil { | 
|  | 30 | +		t.Fatal(err) | 
|  | 31 | +	} | 
|  | 32 | + | 
|  | 33 | +	buf, err := QueryBinary(ctx, conn, make([]byte, 100), "SELECT * FROM t ORDER BY id") | 
|  | 34 | +	if err != nil { | 
|  | 35 | +		t.Fatal(err) | 
|  | 36 | +	} | 
|  | 37 | +	t.Logf("Got %d bytes: %q", len(buf), buf) | 
|  | 38 | + | 
|  | 39 | +	var got []string | 
|  | 40 | +	iter := buf | 
|  | 41 | +	for len(iter) > 0 { | 
|  | 42 | +		t := iter.Next() | 
|  | 43 | +		got = append(got, t.String()) | 
|  | 44 | +		if t.Error { | 
|  | 45 | +			break | 
|  | 46 | +		} | 
|  | 47 | +	} | 
|  | 48 | +	want := []string{ | 
|  | 49 | +		"start-row", "int: -9223372036854775808", "float: 1", "bytes: \"text-a\"", "bytes: \"blob-a\"", "end-row", | 
|  | 50 | +		"start-row", "int: -1", "float: -1", "bytes: \"text-b\"", "bytes: \"blob-b\"", "end-row", | 
|  | 51 | +		"start-row", "int: 0", "float: 0", "bytes: \"text-c\"", "bytes: \"blob-c\"", "end-row", | 
|  | 52 | +		"start-row", "int: 20", "float: 2", "bytes: \"text-d\"", "bytes: \"blob-d\"", "end-row", | 
|  | 53 | +		"start-row", "int: 42", "float: 0.25", "bytes: \"text-f\"", "null", "end-row", | 
|  | 54 | +		"start-row", "int: 43", "float: 1.75", "bytes: \"text-g\"", "null", "end-row", | 
|  | 55 | +		"start-row", "int: 9223372036854775807", "null", "bytes: \"text-e\"", "bytes: \"blob-e\"", "end-row", | 
|  | 56 | +		"end-rows", | 
|  | 57 | +	} | 
|  | 58 | +	if !reflect.DeepEqual(got, want) { | 
|  | 59 | +		t.Errorf("wrong results\n got: %q\nwant: %q\n\ndiff:\n%s", got, want, cmp.Diff(want, got)) | 
|  | 60 | +	} | 
|  | 61 | + | 
|  | 62 | +	allocs := int(testing.AllocsPerRun(10000, func() { | 
|  | 63 | +		_, err := QueryBinary(ctx, conn, buf, "SELECT * FROM t") | 
|  | 64 | +		if err != nil { | 
|  | 65 | +			t.Fatal(err) | 
|  | 66 | +		} | 
|  | 67 | +	})) | 
|  | 68 | +	const maxAllocs = 5 // as of Go 1.20 | 
|  | 69 | +	if allocs > maxAllocs { | 
|  | 70 | +		t.Errorf("allocs = %v; want max %v", allocs, maxAllocs) | 
|  | 71 | +	} | 
|  | 72 | +} | 
0 commit comments