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
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.
// Only bool configuratiton options are supported.
// Only boolean configuration options are supported.
// Called with no arg reads the current configuration 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))
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
pending *Stmt
log func(code xErrorCode, msg string)
arena arena
handle uint32
@@ -258,6 +259,12 @@ func (c *Conn) SetInterrupt(ctx context.Context) (old context.Context) {
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 {
if c, ok := ctx.Value(connKey{}).(*Conn); ok {
if c.interrupt != nil && c.interrupt.Err() != nil {
@@ -267,12 +274,6 @@ func progressCallback(ctx context.Context, mod api.Module, _ uint32) uint32 {
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.
//
// https://sqlite.org/pragma.html

View File

@@ -39,6 +39,7 @@ sqlite3_column_name
sqlite3_column_text
sqlite3_column_type
sqlite3_column_value
sqlite3_config_log_go
sqlite3_create_aggregate_function_go
sqlite3_create_collation_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 {
fsys fs.FS
base string
rowID int64
eof bool
curr entry
next chan entry
done chan struct{}
base string
rowID int64
eof bool
}
type entry struct {
path string
fs.DirEntry
err error
err error
path string
}
func (c *cursor) Close() error {
@@ -180,7 +180,7 @@ func (c *cursor) WalkDirFunc(path string, d fs.DirEntry, err error) error {
select {
case <-c.done:
return fs.SkipAll
case c.next <- entry{path, d, err}:
case c.next <- entry{d, err, path}:
return nil
}
}

View File

@@ -282,6 +282,7 @@ func (a *arena) string(s string) uint32 {
func exportCallbacks(env wazero.HostModuleBuilder) wazero.HostModuleBuilder {
util.ExportFuncII(env, "go_progress", progressCallback)
util.ExportFuncVIII(env, "go_log", logCallback)
util.ExportFuncVI(env, "go_destroy", destroyCallback)
util.ExportFuncVIII(env, "go_func", funcCallback)
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"
// Bindings
#include "func.c"
#include "log.c"
#include "pointer.c"
#include "progress.c"
#include "time.c"

View File

@@ -339,3 +339,28 @@ func TestConn_Config(t *testing.T) {
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")
}
}