Skip to content

Commit cf0d562

Browse files
committed
Integrity.
1 parent a465458 commit cf0d562

File tree

10 files changed

+96
-36
lines changed

10 files changed

+96
-36
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Go, wazero and [`x/sys`](https://pkg.go.dev/golang.org/x/sys) are the _only_ run
3434
- [`github.com/ncruces/go-sqlite3/ext/blobio`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/blobio)
3535
simplifies [incremental BLOB I/O](https://sqlite.org/c3ref/blob_open.html).
3636
- [`github.com/ncruces/go-sqlite3/ext/bloom`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/bloom)
37-
provides the [`bloom_filter`](https://github.com/nalgeon/sqlean/issues/27#issuecomment-1002267134) virtual table.
37+
provides a [Bloom filter](https://github.com/nalgeon/sqlean/issues/27#issuecomment-1002267134) virtual table.
3838
- [`github.com/ncruces/go-sqlite3/ext/csv`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/csv)
3939
reads [comma-separated values](https://sqlite.org/csv.html).
4040
- [`github.com/ncruces/go-sqlite3/ext/fileio`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/fileio)

driver/driver.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ func (c *conn) Raw() *sqlite3.Conn {
229229
return c.Conn
230230
}
231231

232+
// Deprecated: use BeginTx instead.
232233
func (c *conn) Begin() (driver.Tx, error) {
233234
return c.BeginTx(context.Background(), driver.TxOptions{})
234235
}
@@ -559,19 +560,20 @@ func (r *rows) Next(dest []driver.Value) error {
559560
return err
560561
}
561562

562-
func (r *rows) decodeTime(i int, v any) (_ time.Time, _ bool) {
563+
func (r *rows) decodeTime(i int, v any) (_ time.Time, ok bool) {
563564
if r.tmRead == sqlite3.TimeFormatDefault {
565+
// handled by maybeTime
564566
return
565567
}
566-
switch r.declType(i) {
567-
case "DATE", "TIME", "DATETIME", "TIMESTAMP":
568-
// maybe
568+
switch v.(type) {
569+
case int64, float64, string:
570+
// could be a time value
569571
default:
570572
return
571573
}
572-
switch v.(type) {
573-
case int64, float64, string:
574-
// maybe
574+
switch r.declType(i) {
575+
case "DATE", "TIME", "DATETIME", "TIMESTAMP":
576+
// could be a time value
575577
default:
576578
return
577579
}

embed/sqlite3.wasm

56 Bytes
Binary file not shown.

ext/bloom/bloom.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515

1616
"github.com/dchest/siphash"
1717
"github.com/ncruces/go-sqlite3"
18-
"github.com/ncruces/go-sqlite3/internal/util"
1918
)
2019

2120
// Register registers the bloom_filter virtual table:
@@ -161,6 +160,41 @@ func (b *bloom) Rename(new string) error {
161160
return err
162161
}
163162

163+
func (t *bloom) ShadowTables() {}
164+
165+
func (t *bloom) Integrity(schema, table string, flags int) error {
166+
load, _, err := t.db.Prepare(fmt.Sprintf(
167+
`SELECT typeof(data), length(data), p, n, m, k FROM %s.%s WHERE rowid = 1`,
168+
sqlite3.QuoteIdentifier(t.schema), sqlite3.QuoteIdentifier(t.storage)))
169+
if err != nil {
170+
return fmt.Errorf("bloom: %v", err) // can't wrap!
171+
}
172+
defer load.Close()
173+
174+
err = errors.New("bloom: invalid parameters")
175+
if !load.Step() {
176+
return err
177+
}
178+
if t := load.ColumnText(0); t != "blob" {
179+
return err
180+
}
181+
if m := load.ColumnInt64(4); m <= 0 || m%8 != 0 {
182+
return err
183+
} else if load.ColumnInt64(1) != m/8 {
184+
return err
185+
}
186+
if p := load.ColumnFloat(2); p <= 0 || p >= 1 {
187+
return err
188+
}
189+
if n := load.ColumnInt64(3); n <= 0 {
190+
return err
191+
}
192+
if k := load.ColumnInt(5); k <= 0 {
193+
return err
194+
}
195+
return nil
196+
}
197+
164198
func (b *bloom) BestIndex(idx *sqlite3.IndexInfo) error {
165199
for n, cst := range idx.Constraint {
166200
if cst.Usable && cst.Column == 1 &&
@@ -274,8 +308,6 @@ func (c *cursor) Column(ctx *sqlite3.Context, n int) error {
274308
ctx.ResultBool(true)
275309
case 1:
276310
ctx.ResultValue(*c.arg)
277-
default:
278-
panic(util.AssertErr())
279311
}
280312
return nil
281313
}

ext/bloom/bloom_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,14 @@ func Test_compatible(t *testing.T) {
127127
if err != nil {
128128
t.Fatal(err)
129129
}
130+
131+
err = db.Exec(`PRAGMA integrity_check`)
132+
if err != nil {
133+
t.Error(err)
134+
}
135+
136+
err = db.Exec(`PRAGMA quick_check`)
137+
if err != nil {
138+
t.Error(err)
139+
}
130140
}

sqlite3/vtab.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1+
#include <stdbool.h>
12
#include <stddef.h>
23

34
#include "include.h"
45
#include "sqlite3.h"
56

6-
#define SQLITE_VTAB_CREATOR_GO /******/ 0x01
7-
#define SQLITE_VTAB_DESTROYER_GO /****/ 0x02
8-
#define SQLITE_VTAB_UPDATER_GO /******/ 0x04
9-
#define SQLITE_VTAB_RENAMER_GO /******/ 0x08
10-
#define SQLITE_VTAB_OVERLOADER_GO /***/ 0x10
11-
#define SQLITE_VTAB_CHECKER_GO /******/ 0x20
12-
#define SQLITE_VTAB_TXN_GO /**********/ 0x40
13-
#define SQLITE_VTAB_SAVEPOINTER_GO /**/ 0x80
7+
#define SQLITE_VTAB_CREATOR_GO /******/ 0x001
8+
#define SQLITE_VTAB_DESTROYER_GO /****/ 0x002
9+
#define SQLITE_VTAB_UPDATER_GO /******/ 0x004
10+
#define SQLITE_VTAB_RENAMER_GO /******/ 0x008
11+
#define SQLITE_VTAB_OVERLOADER_GO /***/ 0x010
12+
#define SQLITE_VTAB_CHECKER_GO /******/ 0x020
13+
#define SQLITE_VTAB_TXN_GO /**********/ 0x040
14+
#define SQLITE_VTAB_SAVEPOINTER_GO /**/ 0x080
15+
#define SQLITE_VTAB_SHADOWTABS_GO /***/ 0x100
1416

1517
int go_vtab_create(sqlite3_module *, int argc, const char *const *argv,
1618
sqlite3_vtab **, char **pzErr);
@@ -157,6 +159,8 @@ static int go_vtab_integrity_wrapper(sqlite3_vtab *pVTab, const char *zSchema,
157159
return rc;
158160
}
159161

162+
static int go_vtab_shadown_name_wrapper(const char *zName) { return 1; }
163+
160164
int sqlite3_create_module_go(sqlite3 *db, const char *zName, int flags,
161165
go_handle handle) {
162166
struct go_module *mod = malloc(sizeof(struct go_module));
@@ -208,6 +212,9 @@ int sqlite3_create_module_go(sqlite3 *db, const char *zName, int flags,
208212
mod->base.xRelease = go_vtab_release;
209213
mod->base.xRollbackTo = go_vtab_rollback_to;
210214
}
215+
if (flags & SQLITE_VTAB_SHADOWTABS_GO) {
216+
mod->base.xShadowName = go_vtab_shadown_name_wrapper;
217+
}
211218
if (mod->base.xCreate && !mod->base.xDestroy) {
212219
mod->base.xDestroy = mod->base.xDisconnect;
213220
}

vfs/adiantum/README.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
1-
# Go `"adiantum"` SQLite VFS
1+
# Go `adiantum` SQLite VFS
22

33
This package wraps an SQLite VFS to offer encryption at rest.
44

5-
> [!WARNING]
6-
> This work was not certified by a cryptographer.
7-
> If you need vetted encryption, you should purchase the
8-
> [SQLite Encryption Extension](https://sqlite.org/see),
9-
> and either wrap it, or seek assistance wrapping it.
10-
115
The `"adiantum"` VFS wraps the default SQLite VFS using the
126
[Adiantum](https://github.com/lukechampine/adiantum)
137
tweakable and length-preserving encryption.\

vfs/memdb/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Go `"memdb"` SQLite VFS
1+
# Go `memdb` SQLite VFS
22

33
This package implements the [`"memdb"`](https://sqlite.org/src/doc/tip/src/memdb.c)
44
SQLite VFS in pure Go.

vfs/readervfs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Go `"reader"` SQLite VFS
1+
# Go `reader` SQLite VFS
22

33
This package implements a `"reader"` SQLite VFS
44
that allows accessing any [`io.ReaderAt`](https://pkg.go.dev/io#ReaderAt)

vtab.go

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ func CreateModule[T VTab](db *Conn, name string, create, connect VTabConstructor
1616
var flags int
1717

1818
const (
19-
VTAB_CREATOR = 0x01
20-
VTAB_DESTROYER = 0x02
21-
VTAB_UPDATER = 0x04
22-
VTAB_RENAMER = 0x08
23-
VTAB_OVERLOADER = 0x10
24-
VTAB_CHECKER = 0x20
25-
VTAB_TXN = 0x40
26-
VTAB_SAVEPOINTER = 0x80
19+
VTAB_CREATOR = 0x001
20+
VTAB_DESTROYER = 0x002
21+
VTAB_UPDATER = 0x004
22+
VTAB_RENAMER = 0x008
23+
VTAB_OVERLOADER = 0x010
24+
VTAB_CHECKER = 0x020
25+
VTAB_TXN = 0x040
26+
VTAB_SAVEPOINTER = 0x080
27+
VTAB_SHADOWTABS = 0x100
2728
)
2829

2930
if create != nil {
@@ -52,6 +53,9 @@ func CreateModule[T VTab](db *Conn, name string, create, connect VTabConstructor
5253
if implements[VTabSavepointer](vtab) {
5354
flags |= VTAB_SAVEPOINTER
5455
}
56+
if implements[VTabShadowTabler](vtab) {
57+
flags |= VTAB_SHADOWTABS
58+
}
5559

5660
defer db.arena.mark()()
5761
namePtr := db.arena.string(name)
@@ -174,6 +178,17 @@ type VTabOverloader interface {
174178
FindFunction(arg int, name string) (ScalarFunction, IndexConstraintOp)
175179
}
176180

181+
// A VTabShadowTabler allows a virtual table to protect the content
182+
// of shadow tables from being corrupted by hostile SQL.
183+
//
184+
// Implementing this interface signals that a virtual table named
185+
// "mumble" reserves all table names starting with "mumble_".
186+
type VTabShadowTabler interface {
187+
VTab
188+
// https://sqlite.org/vtab.html#the_xshadowname_method
189+
ShadowTables()
190+
}
191+
177192
// A VTabChecker allows a virtual table to report errors
178193
// to the PRAGMA integrity_check and PRAGMA quick_check commands.
179194
//

0 commit comments

Comments
 (0)