-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathsqlite3_opt_vtable_destroy_test.go
More file actions
85 lines (74 loc) · 2.65 KB
/
Copy pathsqlite3_opt_vtable_destroy_test.go
File metadata and controls
85 lines (74 loc) · 2.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//go:build sqlite_vtable || vtable
// +build sqlite_vtable vtable
package sqlite3
import (
"database/sql"
"errors"
"fmt"
"path/filepath"
"sync/atomic"
"testing"
)
type destroyErrModule struct{}
type destroyErrVTab struct{}
func (m destroyErrModule) Create(c *SQLiteConn, args []string) (VTab, error) {
if err := c.DeclareVTab("CREATE TABLE x(test TEXT)"); err != nil {
return nil, err
}
return &destroyErrVTab{}, nil
}
func (m destroyErrModule) Connect(c *SQLiteConn, args []string) (VTab, error) {
return m.Create(c, args)
}
func (m destroyErrModule) DestroyModule() {}
func (v *destroyErrVTab) BestIndex(cst []InfoConstraint, ob []InfoOrderBy) (*IndexResult, error) {
return &IndexResult{Used: make([]bool, len(cst)), EstimatedCost: 100}, nil
}
func (v *destroyErrVTab) Disconnect() error { return nil }
func (v *destroyErrVTab) Destroy() error { return errors.New("boom: destroy refused") }
func (v *destroyErrVTab) Open() (VTabCursor, error) {
return &destroyErrCursor{}, nil
}
type destroyErrCursor struct{}
func (c *destroyErrCursor) Close() error { return nil }
func (c *destroyErrCursor) Filter(idxNum int, idxStr string, vals []any) error {
return nil
}
func (c *destroyErrCursor) Next() error { return nil }
func (c *destroyErrCursor) EOF() bool { return true }
func (c *destroyErrCursor) Column(*SQLiteContext, int) error { return nil }
func (c *destroyErrCursor) Rowid() (int64, error) { return 0, nil }
var destroyErrDriverSeq int32
// TestVTabDestroyErrorThenClose: when xDestroy fails, SQLite retains the
// vtab object and later calls xDisconnect on it during close. The handle
// must stay registered for that call; deleting it on the error path made
// Close panic with a failed type assertion.
func TestVTabDestroyErrorThenClose(t *testing.T) {
// Unique driver name so repeated runs (e.g. -count=2) do not panic on
// duplicate registration.
driverName := fmt.Sprintf("sqlite3_destroy_err_%d", atomic.AddInt32(&destroyErrDriverSeq, 1))
sql.Register(driverName, &SQLiteDriver{
ConnectHook: func(conn *SQLiteConn) error {
return conn.CreateModule("boom", destroyErrModule{})
},
})
db, err := sql.Open(driverName, filepath.Join(t.TempDir(), "vtab.db"))
if err != nil {
t.Fatal(err)
}
if _, err := db.Exec("CREATE VIRTUAL TABLE vtab USING boom()"); err != nil {
t.Fatal(err)
}
rows, err := db.Query("SELECT * FROM vtab")
if err != nil {
t.Fatal(err)
}
rows.Close()
if _, err := db.Exec("DROP TABLE vtab"); err == nil {
t.Fatal("DROP TABLE unexpectedly succeeded with an erroring Destroy")
}
// Must not panic.
if err := db.Close(); err != nil {
t.Logf("close err: %v", err)
}
}