Skip to content

Commit 44c3f9b

Browse files
committed
Coverage, docs.
1 parent 2526fc8 commit 44c3f9b

File tree

6 files changed

+62
-31
lines changed

6 files changed

+62
-31
lines changed

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ as well as direct access to most of the [C SQLite API](https://sqlite.org/cintro
1010

1111
It wraps a [Wasm](https://webassembly.org/) [build](embed/) of SQLite,
1212
and uses [wazero](https://wazero.io/) as the runtime.\
13-
Go, wazero and [`x/sys`](https://pkg.go.dev/golang.org/x/sys) are the _only_ runtime dependencies [^1].
13+
Go, wazero and [`x/sys`](https://pkg.go.dev/golang.org/x/sys) are the _only_ runtime dependencies.
1414

1515
### Getting started
1616

@@ -49,6 +49,8 @@ db.QueryRow(`SELECT sqlite_version()`).Scan(&version)
4949
simplifies [incremental BLOB I/O](https://sqlite.org/c3ref/blob_open.html).
5050
- [`github.com/ncruces/go-sqlite3/ext/bloom`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/bloom)
5151
provides a [Bloom filter](https://github.com/nalgeon/sqlean/issues/27#issuecomment-1002267134) virtual table.
52+
- [`github.com/ncruces/go-sqlite3/ext/closure`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/closure)
53+
provides a transitive closure virtual table.
5254
- [`github.com/ncruces/go-sqlite3/ext/csv`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/csv)
5355
reads [comma-separated values](https://sqlite.org/csv.html).
5456
- [`github.com/ncruces/go-sqlite3/ext/fileio`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/fileio)
@@ -128,7 +130,4 @@ The Wasm and VFS layers are also tested by running SQLite's
128130
- [`modernc.org/sqlite`](https://pkg.go.dev/modernc.org/sqlite)
129131
- [`crawshaw.io/sqlite`](https://pkg.go.dev/crawshaw.io/sqlite)
130132
- [`github.com/mattn/go-sqlite3`](https://pkg.go.dev/github.com/mattn/go-sqlite3)
131-
- [`github.com/zombiezen/go-sqlite`](https://pkg.go.dev/github.com/zombiezen/go-sqlite)
132-
133-
[^1]: anything else you find in `go.mod` is either a test dependency,
134-
or needed by one of the extensions.
133+
- [`github.com/zombiezen/go-sqlite`](https://pkg.go.dev/github.com/zombiezen/go-sqlite)

ext/bloom/bloom.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,6 @@ type cursor struct {
272272
}
273273

274274
func (c *cursor) Filter(idxNum int, idxStr string, arg ...sqlite3.Value) error {
275-
if len(arg) != 1 {
276-
return nil
277-
}
278-
279275
c.eof = false
280276
c.arg = &arg[0]
281277
blob := arg[0].RawBlob()

ext/closure/closure.go

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Package closure provides a transitive closure virtual table.
22
//
3-
// The "transitive_closure" virtual table finds the transitive closure of
3+
// The transitive_closure virtual table finds the transitive closure of
44
// a parent/child relationship in a real table.
55
//
66
// https://sqlite.org/src/doc/tip/ext/misc/closure.c
@@ -24,6 +24,9 @@ const (
2424
_COL_PARENTCOLUMN = 5
2525
)
2626

27+
// Register registers the transitive_closure virtual table:
28+
//
29+
// CREATE VIRTUAL TABLE temp.closure USING transitive_closure;
2730
func Register(db *sqlite3.Conn) error {
2831
return sqlite3.CreateModule(db, "transitive_closure", nil,
2932
func(db *sqlite3.Conn, _, _, _ string, arg ...string) (*closure, error) {
@@ -76,9 +79,9 @@ type closure struct {
7679
func (c *closure) Destroy() error { return nil }
7780

7881
func (c *closure) BestIndex(idx *sqlite3.IndexInfo) error {
79-
posi := 1
8082
plan := 0
81-
cost := 10000000.0
83+
posi := 1
84+
cost := 1e7
8285

8386
for i, cst := range idx.Constraint {
8487
if !cst.Usable {
@@ -140,17 +143,11 @@ func (c *closure) BestIndex(idx *sqlite3.IndexInfo) error {
140143
}
141144
}
142145

143-
if c.table == "" && plan&0xf00 == 0 ||
146+
if plan&1 == 0 ||
147+
c.table == "" && plan&0xf00 == 0 ||
144148
c.column == "" && plan&0xf000 == 0 ||
145149
c.parent == "" && plan&0xf0000 == 0 {
146-
plan = 0
147-
}
148-
if plan&1 == 0 {
149-
plan = 0
150-
cost *= 1e30
151-
for i := range idx.Constraint {
152-
idx.ConstraintUsage[i].ArgvIndex = 0
153-
}
150+
return sqlite3.CONSTRAINT
154151
}
155152

156153
idx.EstimatedCost = cost
@@ -173,10 +170,6 @@ type node struct {
173170
}
174171

175172
func (c *cursor) Filter(idxNum int, idxStr string, arg ...sqlite3.Value) error {
176-
if idxNum&1 == 0 {
177-
return nil
178-
}
179-
180173
root := arg[0].Int64()
181174
maxDepth := math.MaxInt
182175
if idxNum&0xf0 != 0 {

ext/closure/closure_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ func Example() {
2424
}
2525
defer db.Close()
2626

27+
closure.Register(db)
28+
2729
err = db.Exec(`
2830
CREATE TABLE employees (
2931
id INTEGER PRIMARY KEY,
@@ -150,3 +152,33 @@ func TestRegister(t *testing.T) {
150152
t.Fatal(err)
151153
}
152154
}
155+
156+
func Test_errors(t *testing.T) {
157+
t.Parallel()
158+
159+
db, err := sqlite3.Open(":memory:")
160+
if err != nil {
161+
t.Fatal(err)
162+
}
163+
defer db.Close()
164+
165+
err = db.Exec(`CREATE VIRTUAL TABLE hierarchy USING transitive_closure(table='employees')`)
166+
if err == nil {
167+
t.Error("want error")
168+
}
169+
170+
err = db.Exec(`CREATE VIRTUAL TABLE hierarchy USING transitive_closure(tablename='employees', tablename="employees")`)
171+
if err == nil {
172+
t.Error("want error")
173+
}
174+
175+
err = db.Exec("CREATE VIRTUAL TABLE hierarchy USING transitive_closure(tablename=`employees`)")
176+
if err != nil {
177+
t.Error(err)
178+
}
179+
180+
err = db.Exec(`SELECT * FROM hierarchy`)
181+
if err == nil {
182+
t.Error("want error")
183+
}
184+
}

ext/fileio/fsdir.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,22 @@ import (
1010
"github.com/ncruces/go-sqlite3"
1111
)
1212

13+
const (
14+
_COL_NAME = 0
15+
_COL_MODE = 1
16+
_COL_TIME = 2
17+
_COL_DATA = 3
18+
_COL_ROOT = 4
19+
_COL_BASE = 5
20+
)
21+
1322
type fsdir struct{ fsys fs.FS }
1423

1524
func (d fsdir) BestIndex(idx *sqlite3.IndexInfo) error {
1625
var root, base bool
1726
for i, cst := range idx.Constraint {
1827
switch cst.Column {
19-
case 4: // root
28+
case _COL_ROOT:
2029
if !cst.Usable || cst.Op != sqlite3.INDEX_CONSTRAINT_EQ {
2130
return sqlite3.CONSTRAINT
2231
}
@@ -25,7 +34,7 @@ func (d fsdir) BestIndex(idx *sqlite3.IndexInfo) error {
2534
ArgvIndex: 1,
2635
}
2736
root = true
28-
case 5: // base
37+
case _COL_BASE:
2938
if !cst.Usable || cst.Op != sqlite3.INDEX_CONSTRAINT_EQ {
3039
return sqlite3.CONSTRAINT
3140
}
@@ -116,25 +125,25 @@ func (c *cursor) RowID() (int64, error) {
116125

117126
func (c *cursor) Column(ctx sqlite3.Context, n int) error {
118127
switch n {
119-
case 0: // name
128+
case _COL_NAME:
120129
name := strings.TrimPrefix(c.curr.path, c.base)
121130
ctx.ResultText(name)
122131

123-
case 1: // mode
132+
case _COL_MODE:
124133
i, err := c.curr.Info()
125134
if err != nil {
126135
return err
127136
}
128137
ctx.ResultInt64(int64(i.Mode()))
129138

130-
case 2: // mtime
139+
case _COL_TIME:
131140
i, err := c.curr.Info()
132141
if err != nil {
133142
return err
134143
}
135144
ctx.ResultTime(i.ModTime(), sqlite3.TimeFormatUnixFrac)
136145

137-
case 3: // data
146+
case _COL_DATA:
138147
switch typ := c.curr.Type(); {
139148
case typ.IsRegular():
140149
var data []byte

util/vtabutil/arg.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ func Unquote(val string) string {
2626
return val
2727
case '"':
2828
old, new = `""`, `"`
29+
case '`':
30+
old, new = "``", "`"
2931
case '\'':
3032
old, new = `''`, `'`
3133
}

0 commit comments

Comments
 (0)