Error logging.

This commit is contained in:
Nuno Cruces
2023-12-27 14:06:44 +00:00
parent e944d5d8e7
commit d56ee4ac2c
9 changed files with 80 additions and 14 deletions

View File

@@ -1,9 +1,14 @@
package sqlite3 package sqlite3
import "github.com/ncruces/go-sqlite3/internal/util" import (
"context"
"github.com/ncruces/go-sqlite3/internal/util"
"github.com/tetratelabs/wazero/api"
)
// Config makes configuration changes to a database connection. // Config makes configuration changes to a database connection.
// Only bool configuratiton options are supported. // Only boolean configuration options are supported.
// Called with no arg reads the current configuration value, // Called with no arg reads the current configuration value,
// called with one arg sets and returns the new value. // called with one arg sets and returns the new value.
// //
@@ -27,3 +32,26 @@ func (c *Conn) Config(op DBConfig, arg ...bool) (bool, error) {
uint64(op), uint64(argsPtr)) uint64(op), uint64(argsPtr))
return util.ReadUint32(c.mod, argsPtr) != 0, c.error(r) return util.ReadUint32(c.mod, argsPtr) != 0, c.error(r)
} }
// ConfigLog sets up the error logging callback for the connection.
//
// https://www.sqlite.org/errlog.html
func (c *Conn) ConfigLog(cb func(code ExtendedErrorCode, msg string)) error {
var enable uint64
if cb != nil {
enable = 1
}
r := c.call("sqlite3_config_log_go", enable)
if err := c.error(r); err != nil {
return err
}
c.log = cb
return nil
}
func logCallback(ctx context.Context, mod api.Module, _, iCode, zMsg uint32) {
if c, ok := ctx.Value(connKey{}).(*Conn); ok && c.log != nil {
msg := util.ReadString(mod, zMsg, _MAX_LENGTH)
c.log(xErrorCode(iCode), msg)
}
}

13
conn.go
View File

@@ -20,6 +20,7 @@ type Conn struct {
interrupt context.Context interrupt context.Context
pending *Stmt pending *Stmt
log func(code xErrorCode, msg string)
arena arena arena arena
handle uint32 handle uint32
@@ -258,6 +259,12 @@ func (c *Conn) SetInterrupt(ctx context.Context) (old context.Context) {
return old return old
} }
func (c *Conn) checkInterrupt() {
if c.interrupt != nil && c.interrupt.Err() != nil {
c.call("sqlite3_interrupt", uint64(c.handle))
}
}
func progressCallback(ctx context.Context, mod api.Module, _ uint32) uint32 { func progressCallback(ctx context.Context, mod api.Module, _ uint32) uint32 {
if c, ok := ctx.Value(connKey{}).(*Conn); ok { if c, ok := ctx.Value(connKey{}).(*Conn); ok {
if c.interrupt != nil && c.interrupt.Err() != nil { if c.interrupt != nil && c.interrupt.Err() != nil {
@@ -267,12 +274,6 @@ func progressCallback(ctx context.Context, mod api.Module, _ uint32) uint32 {
return 0 return 0
} }
func (c *Conn) checkInterrupt() {
if c.interrupt != nil && c.interrupt.Err() != nil {
c.call("sqlite3_interrupt", uint64(c.handle))
}
}
// Pragma executes a PRAGMA statement and returns any results. // Pragma executes a PRAGMA statement and returns any results.
// //
// https://sqlite.org/pragma.html // https://sqlite.org/pragma.html

View File

@@ -39,6 +39,7 @@ sqlite3_column_name
sqlite3_column_text sqlite3_column_text
sqlite3_column_type sqlite3_column_type
sqlite3_column_value sqlite3_column_value
sqlite3_config_log_go
sqlite3_create_aggregate_function_go sqlite3_create_aggregate_function_go
sqlite3_create_collation_go sqlite3_create_collation_go
sqlite3_create_function_go sqlite3_create_function_go

Binary file not shown.

View File

@@ -53,18 +53,18 @@ func (d fsdir) Open() (sqlite3.VTabCursor, error) {
type cursor struct { type cursor struct {
fsys fs.FS fsys fs.FS
base string
rowID int64
eof bool
curr entry curr entry
next chan entry next chan entry
done chan struct{} done chan struct{}
base string
rowID int64
eof bool
} }
type entry struct { type entry struct {
path string
fs.DirEntry fs.DirEntry
err error err error
path string
} }
func (c *cursor) Close() error { func (c *cursor) Close() error {
@@ -180,7 +180,7 @@ func (c *cursor) WalkDirFunc(path string, d fs.DirEntry, err error) error {
select { select {
case <-c.done: case <-c.done:
return fs.SkipAll return fs.SkipAll
case c.next <- entry{path, d, err}: case c.next <- entry{d, err, path}:
return nil return nil
} }
} }

View File

@@ -282,6 +282,7 @@ func (a *arena) string(s string) uint32 {
func exportCallbacks(env wazero.HostModuleBuilder) wazero.HostModuleBuilder { func exportCallbacks(env wazero.HostModuleBuilder) wazero.HostModuleBuilder {
util.ExportFuncII(env, "go_progress", progressCallback) util.ExportFuncII(env, "go_progress", progressCallback)
util.ExportFuncVIII(env, "go_log", logCallback)
util.ExportFuncVI(env, "go_destroy", destroyCallback) util.ExportFuncVI(env, "go_destroy", destroyCallback)
util.ExportFuncVIII(env, "go_func", funcCallback) util.ExportFuncVIII(env, "go_func", funcCallback)
util.ExportFuncVIII(env, "go_step", stepCallback) util.ExportFuncVIII(env, "go_step", stepCallback)

9
sqlite3/log.c Normal file
View File

@@ -0,0 +1,9 @@
#include <stdbool.h>
#include "sqlite3.h"
void go_log(void*, int, const char*);
int sqlite3_config_log_go(bool enable) {
return sqlite3_config(SQLITE_CONFIG_LOG, enable ? go_log : NULL, NULL);
}

View File

@@ -10,6 +10,7 @@
#include "ext/uuid.c" #include "ext/uuid.c"
// Bindings // Bindings
#include "func.c" #include "func.c"
#include "log.c"
#include "pointer.c" #include "pointer.c"
#include "progress.c" #include "progress.c"
#include "time.c" #include "time.c"

View File

@@ -339,3 +339,28 @@ func TestConn_Config(t *testing.T) {
t.Error("want false") t.Error("want false")
} }
} }
func TestConn_ConfigLog(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
var code sqlite3.ExtendedErrorCode
err = db.ConfigLog(func(c sqlite3.ExtendedErrorCode, msg string) {
t.Log(msg)
code = c
})
if err != nil {
t.Fatal(err)
}
db.Prepare(`SELECT * FRM sqlite_schema`)
if code != sqlite3.ExtendedErrorCode(sqlite3.ERROR) {
t.Error("want sqlite3.ERROR")
}
}