Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions sqlite3/sqlite3.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ package sqlite3
#cgo CFLAGS: -DSQLITE_ENABLE_STAT4=1
#cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY
#cgo CFLAGS: -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
#cgo CFLAGS: -DSQLITE_OMIT_AUTHORIZATION=1
#cgo CFLAGS: -DSQLITE_OMIT_AUTOINIT=1
#cgo CFLAGS: -DSQLITE_OMIT_DEPRECATED=1
#cgo CFLAGS: -DSQLITE_OMIT_PROGRESS_CALLBACK=1
Expand Down Expand Up @@ -102,12 +101,13 @@ int go_busy_handler(void*,int);
int go_commit_hook(void*);
void go_rollback_hook(void*);
void go_update_hook(void* data, int op,const char *db, const char *tbl, sqlite3_int64 row);
int go_set_authorizer(void* data, int op, const char *arg1, const char *arg2, const char *db, const char *entity);

SET(busy_handler)
SET(commit_hook)
SET(rollback_hook)
SET(update_hook)

SET(set_authorizer)

// A pointer to an instance of this structure is passed as the user-context
// pointer when registering for an unlock-notify callback.
Expand Down Expand Up @@ -259,6 +259,7 @@ var busyRegistry = newRegistry()
var commitRegistry = newRegistry()
var rollbackRegistry = newRegistry()
var updateRegistry = newRegistry()
var authorizerRegistry = newRegistry()

func init() {
// Initialize SQLite (required with SQLITE_OMIT_AUTOINIT).
Expand All @@ -280,10 +281,11 @@ func init() {
type Conn struct {
db *C.sqlite3

busyIdx int
commitIdx int
rollbackIdx int
updateIdx int
busyIdx int
commitIdx int
rollbackIdx int
updateIdx int
authorizerIdx int
}

// Open creates a new connection to a SQLite database. The name can be 1) a path
Expand Down Expand Up @@ -1352,3 +1354,18 @@ func (c *Conn) UpdateFunc(f UpdateFunc) (prev UpdateFunc) {
prev, _ = updateRegistry.unregister(prevIdx).(UpdateFunc)
return
}

// AuthorizerFunc registers a function that is invoked by SQLite During sql
// statement compilation. Function can return sqlite3.OK to accept statement,
// sqlite3.IGNORE to disallow specyfic action, but allow further statement
// processing, or sqlite3.DENY to deny action completly and stop processing.
//
// [https://www.sqlite.org/c3ref/set_authorizer.html]
func (c *Conn) AuthorizerFunc(f AuthorizerFunc) (prev AuthorizerFunc) {
idx := authorizerRegistry.register(f)
prevIdx := c.authorizerIdx
c.authorizerIdx = idx
C.set_set_authorizer(c.db, unsafe.Pointer(&c.authorizerIdx), cBool(f != nil))
prev, _ = authorizerRegistry.unregister(prevIdx).(AuthorizerFunc)
return
}
30 changes: 30 additions & 0 deletions sqlite3/sqlite3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,36 @@ func TestUpdateHandler(T *testing.T) {
verify(&update{DELETE, "main", "x", 2})
}

func TestAuthorizerHandler(T *testing.T) {
t := begin(T)
defer t.skipRestIfFailed()

c := t.open(":memory:")
defer t.close(c)
t.exec(c, "CREATE TABLE x(a)")

type authorizer struct {
op int
arg1, arg2, db, entity string
}
var have *authorizer
verify := func(want *authorizer) {
if !reflect.DeepEqual(have, want) {
t.Fatalf(cl("verify() expected %v; got %v"), want, have)
}
}
c.AuthorizerFunc(func(op int, arg1, arg2, db, entity RawString) int {
have = &authorizer{op, arg1.Copy(), arg2.Copy(), db.Copy(), entity.Copy()}
return OK
})

t.exec(c, "INSERT INTO x VALUES(1)")
verify(&authorizer{INSERT, "x", "", "main", ""})

t.exec(c, "SELECT * FROM x")
verify(&authorizer{READ, "x", "a", "main", ""})
}

func TestBusyHandler(T *testing.T) {
t := begin(T)

Expand Down
10 changes: 10 additions & 0 deletions sqlite3/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ type RollbackFunc func()
// inserted, or deleted.
type UpdateFunc func(op int, db, tbl RawString, row int64)

// AuthorizerFunc is a callback function invoked by SQLite when statement is compiled.
type AuthorizerFunc func(op int, arg1, arg2, db, entity RawString) int

// Error is returned for all SQLite API result codes other than OK, ROW, and
// DONE.
type Error struct {
Expand Down Expand Up @@ -383,3 +386,10 @@ func go_update_hook(data unsafe.Pointer, op C.int, db, tbl *C.char, row C.sqlite
fn := updateRegistry.lookup(idx).(UpdateFunc)
fn(int(op), raw(goStr(db)), raw(goStr(tbl)), int64(row))
}

//export go_set_authorizer
func go_set_authorizer(data unsafe.Pointer, op C.int, arg1, arg2, db, entity *C.char) C.int {
idx := *(*int)(data)
fn := authorizerRegistry.lookup(idx).(AuthorizerFunc)
return C.int(fn(int(op), raw(goStr(arg1)), raw(goStr(arg2)), raw(goStr(db)), raw(goStr(entity))))
}