diff --git a/ext/array/array_test.go b/ext/array/array_test.go index d1d5b238..51b406de 100644 --- a/ext/array/array_test.go +++ b/ext/array/array_test.go @@ -52,6 +52,8 @@ func Example() { } func Test_cursor_Column(t *testing.T) { + t.Parallel() + db, err := driver.Open(":memory:", func(c *sqlite3.Conn) error { array.Register(c) return nil diff --git a/ext/blob/blob.go b/ext/blob/blob.go index 111166bd..d0093f14 100644 --- a/ext/blob/blob.go +++ b/ext/blob/blob.go @@ -60,10 +60,10 @@ func openBlob(ctx sqlite3.Context, arg ...sqlite3.Value) { } // This ensures the blob is closed if db, table, column or write change. - ctx.SetAuxData(0, blob) - ctx.SetAuxData(1, blob) - ctx.SetAuxData(2, blob) - ctx.SetAuxData(4, blob) + ctx.SetAuxData(0, blob) // db + ctx.SetAuxData(1, blob) // table + ctx.SetAuxData(2, blob) // column + ctx.SetAuxData(4, blob) // write } // OpenCallback is the type for the blob_open callback. diff --git a/ext/blob/blob_test.go b/ext/blob/blob_test.go index 58c65898..68fdcc5b 100644 --- a/ext/blob/blob_test.go +++ b/ext/blob/blob_test.go @@ -4,10 +4,13 @@ import ( "io" "log" "os" + "reflect" + "testing" "github.com/ncruces/go-sqlite3" "github.com/ncruces/go-sqlite3/driver" _ "github.com/ncruces/go-sqlite3/embed" + "github.com/ncruces/go-sqlite3/ext/array" "github.com/ncruces/go-sqlite3/ext/blob" _ "github.com/ncruces/go-sqlite3/vfs/memdb" ) @@ -59,3 +62,67 @@ func Example() { // Output: // Hello BLOB! } + +func TestRegister(t *testing.T) { + t.Parallel() + + db, err := sqlite3.Open(":memory:") + if err != nil { + t.Fatal(err) + } + defer db.Close() + + blob.Register(db) + array.Register(db) + + err = db.Exec(`SELECT blob_open()`) + if err == nil { + t.Fatal("want error") + } else { + t.Log(err) + } + + err = db.Exec(` + CREATE TABLE IF NOT EXISTS test1 (col); + CREATE TABLE IF NOT EXISTS test2 (col); + INSERT INTO test1 VALUES (x'cafe'); + INSERT INTO test2 VALUES (x'babe'); + `) + if err != nil { + t.Fatal(err) + } + + stmt, _, err := db.Prepare(`SELECT blob_open('main', value, 'col', 1, false, ?) FROM array(?)`) + if err != nil { + t.Fatal(err) + } + defer stmt.Close() + + var got []string + err = stmt.BindPointer(1, blob.OpenCallback(func(b *sqlite3.Blob, _ ...sqlite3.Value) error { + d, err := io.ReadAll(b) + if err != nil { + return err + } + got = append(got, string(d)) + return nil + })) + if err != nil { + t.Fatal(err) + } + + err = stmt.BindPointer(2, []string{"test1", "test2"}) + if err != nil { + t.Fatal(err) + } + + err = stmt.Exec() + if err != nil { + t.Fatal(err) + } + + want := []string{"\xca\xfe", "\xba\xbe"} + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, want %v", got, want) + } +} diff --git a/ext/csv/csv_test.go b/ext/csv/csv_test.go index c9bfe621..5431203f 100644 --- a/ext/csv/csv_test.go +++ b/ext/csv/csv_test.go @@ -51,6 +51,8 @@ func Example() { } func TestRegister(t *testing.T) { + t.Parallel() + db, err := sqlite3.Open(":memory:") if err != nil { t.Fatal(err) @@ -106,6 +108,8 @@ Robert "Griesemer" "gri"` } func TestRegister_errors(t *testing.T) { + t.Parallel() + db, err := sqlite3.Open(":memory:") if err != nil { t.Fatal(err) diff --git a/ext/csv/params_test.go b/ext/csv/params_test.go index 97a6b4b7..d7f05843 100644 --- a/ext/csv/params_test.go +++ b/ext/csv/params_test.go @@ -3,6 +3,8 @@ package csv import "testing" func Test_uintParam(t *testing.T) { + t.Parallel() + tests := []struct { arg string key string diff --git a/ext/csv/schema_test.go b/ext/csv/schema_test.go index eb1aba9c..f00a4567 100644 --- a/ext/csv/schema_test.go +++ b/ext/csv/schema_test.go @@ -3,6 +3,8 @@ package csv import "testing" func Test_getSchema(t *testing.T) { + t.Parallel() + tests := []struct { header bool columns int diff --git a/ext/lines/lines_test.go b/ext/lines/lines_test.go index d0912b1b..310b0378 100644 --- a/ext/lines/lines_test.go +++ b/ext/lines/lines_test.go @@ -67,6 +67,8 @@ func Example() { } func Test_lines(t *testing.T) { + t.Parallel() + db, err := driver.Open(":memory:", func(c *sqlite3.Conn) error { lines.Register(c) return nil @@ -95,6 +97,8 @@ func Test_lines(t *testing.T) { } func Test_lines_error(t *testing.T) { + t.Parallel() + db, err := driver.Open(":memory:", func(c *sqlite3.Conn) error { lines.Register(c) return nil @@ -120,6 +124,8 @@ func Test_lines_error(t *testing.T) { } func Test_lines_read(t *testing.T) { + t.Parallel() + db, err := driver.Open(":memory:", func(c *sqlite3.Conn) error { lines.Register(c) return nil @@ -149,6 +155,8 @@ func Test_lines_read(t *testing.T) { } func Test_lines_test(t *testing.T) { + t.Parallel() + db, err := driver.Open(":memory:", func(c *sqlite3.Conn) error { lines.Register(c) return nil diff --git a/ext/statement/stmt.go b/ext/statement/stmt.go index 627f2206..55d5df28 100644 --- a/ext/statement/stmt.go +++ b/ext/statement/stmt.go @@ -16,7 +16,7 @@ import ( // Register registers the statement virtual table. func Register(db *sqlite3.Conn) { declare := func(db *sqlite3.Conn, _, _, _ string, arg ...string) (_ *table, err error) { - if arg == nil || len(arg[0]) < 3 { + if len(arg) == 0 || len(arg[0]) < 3 { return nil, fmt.Errorf("statement: no statement provided") } sql := arg[0] @@ -70,21 +70,19 @@ func (t *table) declare() error { str.WriteString(sep) name := stmt.ColumnName(i) str.WriteString(sqlite3.QuoteIdentifier(name)) - if typ := stmt.ColumnDeclType(i); typ != "" { - str.WriteByte(' ') - str.WriteString(typ) - } + str.WriteByte(' ') + str.WriteString(stmt.ColumnDeclType(i)) sep = "," } for i := 1; i <= t.inputs; i++ { str.WriteString(sep) name := stmt.BindName(i) if name == "" { - str.WriteString("'") + str.WriteString("[") str.WriteString(strconv.Itoa(i)) - str.WriteString("' HIDDEN") + str.WriteString("] HIDDEN") } else { - str.WriteString(sqlite3.QuoteIdentifier(name)) + str.WriteString(sqlite3.QuoteIdentifier(name[1:])) str.WriteString(" HIDDEN") } sep = "," diff --git a/ext/statement/stmt_test.go b/ext/statement/stmt_test.go index 29137fab..208edcfb 100644 --- a/ext/statement/stmt_test.go +++ b/ext/statement/stmt_test.go @@ -3,6 +3,7 @@ package statement_test import ( "fmt" "log" + "testing" "github.com/ncruces/go-sqlite3" _ "github.com/ncruces/go-sqlite3/embed" @@ -45,3 +46,101 @@ func Example() { // Output: // Twosday was 2022-2-22 } + +func TestRegister(t *testing.T) { + t.Parallel() + + db, err := sqlite3.Open(":memory:") + if err != nil { + t.Fatal(err) + } + defer db.Close() + + statement.Register(db) + + err = db.Exec(` + CREATE VIRTUAL TABLE arguments USING statement((SELECT ? AS a, ? AS b, ? AS c)) + `) + if err != nil { + t.Fatal(err) + } + + err = db.Exec(` + SELECT * from arguments WHERE [2] = 'y' AND [3] = 'z' + `) + if err != nil { + t.Fatal(err) + } + + err = db.Exec(` + CREATE VIRTUAL TABLE hypot USING statement((SELECT sqrt(:x * :x + :y * :y) AS hypotenuse)) + `) + if err != nil { + t.Fatal(err) + } + + stmt, _, err := db.Prepare(` + SELECT x, y, * FROM hypot WHERE x = 3 AND y = 4 + `) + if err != nil { + t.Fatal(err) + } + defer stmt.Close() + + if stmt.Step() { + x := stmt.ColumnInt(0) + y := stmt.ColumnInt(1) + hypot := stmt.ColumnInt(2) + if x != 3 || y != 4 || hypot != 5 { + t.Errorf("hypot(%d, %d) = %d", x, y, hypot) + } + } + +} + +func TestRegister_errors(t *testing.T) { + t.Parallel() + + db, err := sqlite3.Open(":memory:") + if err != nil { + t.Fatal(err) + } + defer db.Close() + + statement.Register(db) + + err = db.Exec(`CREATE VIRTUAL TABLE split_date USING statement()`) + if err == nil { + t.Fatal("want error") + } else { + t.Log(err) + } + + err = db.Exec(`CREATE VIRTUAL TABLE split_date USING statement(SELECT 1, SELECT 2)`) + if err == nil { + t.Fatal("want error") + } else { + t.Log(err) + } + + err = db.Exec(`CREATE VIRTUAL TABLE split_date USING statement((SELECT 1, SELECT 2))`) + if err == nil { + t.Fatal("want error") + } else { + t.Log(err) + } + + err = db.Exec(`CREATE VIRTUAL TABLE split_date USING statement((SELECT 1; SELECT 2))`) + if err == nil { + t.Fatal("want error") + } else { + t.Log(err) + } + + err = db.Exec(`CREATE VIRTUAL TABLE split_date USING statement((CREATE TABLE x(val)))`) + if err == nil { + t.Fatal("want error") + } else { + t.Log(err) + } +} diff --git a/ext/stats/welford_test.go b/ext/stats/welford_test.go index 405053e0..93c63366 100644 --- a/ext/stats/welford_test.go +++ b/ext/stats/welford_test.go @@ -6,6 +6,8 @@ import ( ) func Test_welford(t *testing.T) { + t.Parallel() + var s1, s2 welford s1.enqueue(4) @@ -38,6 +40,8 @@ func Test_welford(t *testing.T) { } func Test_covar(t *testing.T) { + t.Parallel() + var c1, c2 welford2 c1.enqueue(3, 70) @@ -64,6 +68,8 @@ func Test_covar(t *testing.T) { } func Test_correlation(t *testing.T) { + t.Parallel() + var c welford2 c.enqueue(1, 3) c.enqueue(2, 2) diff --git a/ext/unicode/unicode_test.go b/ext/unicode/unicode_test.go index 3f37ff42..123d2474 100644 --- a/ext/unicode/unicode_test.go +++ b/ext/unicode/unicode_test.go @@ -189,6 +189,8 @@ func TestRegister_error(t *testing.T) { } func Test_like2regex(t *testing.T) { + t.Parallel() + const prefix = `(?is)\A` const sufix = `\z` tests := []struct {