Skip to content

Commit

Permalink
Integrity.
Browse files Browse the repository at this point in the history
  • Loading branch information
ncruces committed Jun 21, 2024
1 parent a465458 commit cf0d562
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 36 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Go, wazero and [`x/sys`](https://pkg.go.dev/golang.org/x/sys) are the _only_ run
- [`github.com/ncruces/go-sqlite3/ext/blobio`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/blobio)
simplifies [incremental BLOB I/O](https://sqlite.org/c3ref/blob_open.html).
- [`github.com/ncruces/go-sqlite3/ext/bloom`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/bloom)
provides the [`bloom_filter`](https://github.com/nalgeon/sqlean/issues/27#issuecomment-1002267134) virtual table.
provides a [Bloom filter](https://github.com/nalgeon/sqlean/issues/27#issuecomment-1002267134) virtual table.
- [`github.com/ncruces/go-sqlite3/ext/csv`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/csv)
reads [comma-separated values](https://sqlite.org/csv.html).
- [`github.com/ncruces/go-sqlite3/ext/fileio`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/fileio)
Expand Down
16 changes: 9 additions & 7 deletions driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ func (c *conn) Raw() *sqlite3.Conn {
return c.Conn
}

// Deprecated: use BeginTx instead.
func (c *conn) Begin() (driver.Tx, error) {
return c.BeginTx(context.Background(), driver.TxOptions{})
}
Expand Down Expand Up @@ -559,19 +560,20 @@ func (r *rows) Next(dest []driver.Value) error {
return err
}

func (r *rows) decodeTime(i int, v any) (_ time.Time, _ bool) {
func (r *rows) decodeTime(i int, v any) (_ time.Time, ok bool) {
if r.tmRead == sqlite3.TimeFormatDefault {
// handled by maybeTime
return
}
switch r.declType(i) {
case "DATE", "TIME", "DATETIME", "TIMESTAMP":
// maybe
switch v.(type) {
case int64, float64, string:
// could be a time value
default:
return
}
switch v.(type) {
case int64, float64, string:
// maybe
switch r.declType(i) {
case "DATE", "TIME", "DATETIME", "TIMESTAMP":
// could be a time value
default:
return
}
Expand Down
Binary file modified embed/sqlite3.wasm
Binary file not shown.
38 changes: 35 additions & 3 deletions ext/bloom/bloom.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (

"github.com/dchest/siphash"
"github.com/ncruces/go-sqlite3"
"github.com/ncruces/go-sqlite3/internal/util"
)

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

func (t *bloom) ShadowTables() {}

func (t *bloom) Integrity(schema, table string, flags int) error {
load, _, err := t.db.Prepare(fmt.Sprintf(
`SELECT typeof(data), length(data), p, n, m, k FROM %s.%s WHERE rowid = 1`,
sqlite3.QuoteIdentifier(t.schema), sqlite3.QuoteIdentifier(t.storage)))
if err != nil {
return fmt.Errorf("bloom: %v", err) // can't wrap!
}
defer load.Close()

err = errors.New("bloom: invalid parameters")
if !load.Step() {
return err
}
if t := load.ColumnText(0); t != "blob" {
return err
}
if m := load.ColumnInt64(4); m <= 0 || m%8 != 0 {
return err
} else if load.ColumnInt64(1) != m/8 {
return err
}
if p := load.ColumnFloat(2); p <= 0 || p >= 1 {
return err
}
if n := load.ColumnInt64(3); n <= 0 {
return err
}
if k := load.ColumnInt(5); k <= 0 {
return err
}
return nil
}

func (b *bloom) BestIndex(idx *sqlite3.IndexInfo) error {
for n, cst := range idx.Constraint {
if cst.Usable && cst.Column == 1 &&
Expand Down Expand Up @@ -274,8 +308,6 @@ func (c *cursor) Column(ctx *sqlite3.Context, n int) error {
ctx.ResultBool(true)
case 1:
ctx.ResultValue(*c.arg)
default:
panic(util.AssertErr())
}
return nil
}
Expand Down
10 changes: 10 additions & 0 deletions ext/bloom/bloom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,14 @@ func Test_compatible(t *testing.T) {
if err != nil {
t.Fatal(err)
}

err = db.Exec(`PRAGMA integrity_check`)
if err != nil {
t.Error(err)
}

err = db.Exec(`PRAGMA quick_check`)
if err != nil {
t.Error(err)
}
}
23 changes: 15 additions & 8 deletions sqlite3/vtab.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
#include <stdbool.h>
#include <stddef.h>

#include "include.h"
#include "sqlite3.h"

#define SQLITE_VTAB_CREATOR_GO /******/ 0x01
#define SQLITE_VTAB_DESTROYER_GO /****/ 0x02
#define SQLITE_VTAB_UPDATER_GO /******/ 0x04
#define SQLITE_VTAB_RENAMER_GO /******/ 0x08
#define SQLITE_VTAB_OVERLOADER_GO /***/ 0x10
#define SQLITE_VTAB_CHECKER_GO /******/ 0x20
#define SQLITE_VTAB_TXN_GO /**********/ 0x40
#define SQLITE_VTAB_SAVEPOINTER_GO /**/ 0x80
#define SQLITE_VTAB_CREATOR_GO /******/ 0x001
#define SQLITE_VTAB_DESTROYER_GO /****/ 0x002
#define SQLITE_VTAB_UPDATER_GO /******/ 0x004
#define SQLITE_VTAB_RENAMER_GO /******/ 0x008
#define SQLITE_VTAB_OVERLOADER_GO /***/ 0x010
#define SQLITE_VTAB_CHECKER_GO /******/ 0x020
#define SQLITE_VTAB_TXN_GO /**********/ 0x040
#define SQLITE_VTAB_SAVEPOINTER_GO /**/ 0x080
#define SQLITE_VTAB_SHADOWTABS_GO /***/ 0x100

int go_vtab_create(sqlite3_module *, int argc, const char *const *argv,
sqlite3_vtab **, char **pzErr);
Expand Down Expand Up @@ -157,6 +159,8 @@ static int go_vtab_integrity_wrapper(sqlite3_vtab *pVTab, const char *zSchema,
return rc;
}

static int go_vtab_shadown_name_wrapper(const char *zName) { return 1; }

int sqlite3_create_module_go(sqlite3 *db, const char *zName, int flags,
go_handle handle) {
struct go_module *mod = malloc(sizeof(struct go_module));
Expand Down Expand Up @@ -208,6 +212,9 @@ int sqlite3_create_module_go(sqlite3 *db, const char *zName, int flags,
mod->base.xRelease = go_vtab_release;
mod->base.xRollbackTo = go_vtab_rollback_to;
}
if (flags & SQLITE_VTAB_SHADOWTABS_GO) {
mod->base.xShadowName = go_vtab_shadown_name_wrapper;
}
if (mod->base.xCreate && !mod->base.xDestroy) {
mod->base.xDestroy = mod->base.xDisconnect;
}
Expand Down
8 changes: 1 addition & 7 deletions vfs/adiantum/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
# Go `"adiantum"` SQLite VFS
# Go `adiantum` SQLite VFS

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

> [!WARNING]
> This work was not certified by a cryptographer.
> If you need vetted encryption, you should purchase the
> [SQLite Encryption Extension](https://sqlite.org/see),
> and either wrap it, or seek assistance wrapping it.
The `"adiantum"` VFS wraps the default SQLite VFS using the
[Adiantum](https://github.com/lukechampine/adiantum)
tweakable and length-preserving encryption.\
Expand Down
2 changes: 1 addition & 1 deletion vfs/memdb/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Go `"memdb"` SQLite VFS
# Go `memdb` SQLite VFS

This package implements the [`"memdb"`](https://sqlite.org/src/doc/tip/src/memdb.c)
SQLite VFS in pure Go.
Expand Down
2 changes: 1 addition & 1 deletion vfs/readervfs/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Go `"reader"` SQLite VFS
# Go `reader` SQLite VFS

This package implements a `"reader"` SQLite VFS
that allows accessing any [`io.ReaderAt`](https://pkg.go.dev/io#ReaderAt)
Expand Down
31 changes: 23 additions & 8 deletions vtab.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ func CreateModule[T VTab](db *Conn, name string, create, connect VTabConstructor
var flags int

const (
VTAB_CREATOR = 0x01
VTAB_DESTROYER = 0x02
VTAB_UPDATER = 0x04
VTAB_RENAMER = 0x08
VTAB_OVERLOADER = 0x10
VTAB_CHECKER = 0x20
VTAB_TXN = 0x40
VTAB_SAVEPOINTER = 0x80
VTAB_CREATOR = 0x001
VTAB_DESTROYER = 0x002
VTAB_UPDATER = 0x004
VTAB_RENAMER = 0x008
VTAB_OVERLOADER = 0x010
VTAB_CHECKER = 0x020
VTAB_TXN = 0x040
VTAB_SAVEPOINTER = 0x080
VTAB_SHADOWTABS = 0x100
)

if create != nil {
Expand Down Expand Up @@ -52,6 +53,9 @@ func CreateModule[T VTab](db *Conn, name string, create, connect VTabConstructor
if implements[VTabSavepointer](vtab) {
flags |= VTAB_SAVEPOINTER
}
if implements[VTabShadowTabler](vtab) {
flags |= VTAB_SHADOWTABS
}

defer db.arena.mark()()
namePtr := db.arena.string(name)
Expand Down Expand Up @@ -174,6 +178,17 @@ type VTabOverloader interface {
FindFunction(arg int, name string) (ScalarFunction, IndexConstraintOp)
}

// A VTabShadowTabler allows a virtual table to protect the content
// of shadow tables from being corrupted by hostile SQL.
//
// Implementing this interface signals that a virtual table named
// "mumble" reserves all table names starting with "mumble_".
type VTabShadowTabler interface {
VTab
// https://sqlite.org/vtab.html#the_xshadowname_method
ShadowTables()
}

// A VTabChecker allows a virtual table to report errors
// to the PRAGMA integrity_check and PRAGMA quick_check commands.
//
Expand Down

0 comments on commit cf0d562

Please sign in to comment.