diff --git a/const.go b/const.go index 11eb33c..e4c7d72 100644 --- a/const.go +++ b/const.go @@ -7,13 +7,10 @@ const ( _ROW = 100 /* sqlite3_step() has another row ready */ _DONE = 101 /* sqlite3_step() has finished executing */ - _UTF8 = 1 - - _MAX_NAME = 1e6 // Self-imposed limit for most NUL terminated strings. - _MAX_LENGTH = 1e9 - _MAX_SQL_LENGTH = 1e9 - _MAX_ALLOCATION_SIZE = 0x7ffffeff - _MAX_FUNCTION_ARG = 100 + _MAX_NAME = 1e6 // Self-imposed limit for most NUL terminated strings. + _MAX_LENGTH = 1e9 + _MAX_SQL_LENGTH = 1e9 + _MAX_FUNCTION_ARG = 100 ptrlen = 4 ) diff --git a/context.go b/context.go index 4fcda56..be5dd92 100644 --- a/context.go +++ b/context.go @@ -84,9 +84,8 @@ func (ctx Context) ResultFloat(value float64) { // https://sqlite.org/c3ref/result_blob.html func (ctx Context) ResultText(value string) { ptr := ctx.c.newString(value) - ctx.c.call("sqlite3_result_text64", - uint64(ctx.handle), uint64(ptr), uint64(len(value)), - uint64(ctx.c.freer), _UTF8) + ctx.c.call("sqlite3_result_text_go", + uint64(ctx.handle), uint64(ptr), uint64(len(value))) } // ResultRawText sets the text result of the function to a []byte. @@ -94,9 +93,8 @@ func (ctx Context) ResultText(value string) { // https://sqlite.org/c3ref/result_blob.html func (ctx Context) ResultRawText(value []byte) { ptr := ctx.c.newBytes(value) - ctx.c.call("sqlite3_result_text64", - uint64(ctx.handle), uint64(ptr), uint64(len(value)), - uint64(ctx.c.freer), _UTF8) + ctx.c.call("sqlite3_result_text_go", + uint64(ctx.handle), uint64(ptr), uint64(len(value))) } // ResultBlob sets the result of the function to a []byte. @@ -105,9 +103,8 @@ func (ctx Context) ResultRawText(value []byte) { // https://sqlite.org/c3ref/result_blob.html func (ctx Context) ResultBlob(value []byte) { ptr := ctx.c.newBytes(value) - ctx.c.call("sqlite3_result_blob64", - uint64(ctx.handle), uint64(ptr), uint64(len(value)), - uint64(ctx.c.freer)) + ctx.c.call("sqlite3_result_blob_go", + uint64(ctx.handle), uint64(ptr), uint64(len(value))) } // ResultZeroBlob sets the result of the function to a zero-filled, length n BLOB. @@ -154,9 +151,8 @@ func (ctx Context) resultRFC3339Nano(value time.Time) { buf := util.View(ctx.c.mod, ptr, maxlen) buf = value.AppendFormat(buf[:0], time.RFC3339Nano) - ctx.c.call("sqlite3_result_text64", - uint64(ctx.handle), uint64(ptr), uint64(len(buf)), - uint64(ctx.c.freer), _UTF8) + ctx.c.call("sqlite3_result_text_go", + uint64(ctx.handle), uint64(ptr), uint64(len(buf))) } // ResultPointer sets the result of the function to NULL, just like [Context.ResultNull], diff --git a/embed/bcw2/bcw2.wasm b/embed/bcw2/bcw2.wasm index fcf23b1..b851bcb 100755 Binary files a/embed/bcw2/bcw2.wasm and b/embed/bcw2/bcw2.wasm differ diff --git a/embed/exports.txt b/embed/exports.txt index e7882cb..0123605 100644 --- a/embed/exports.txt +++ b/embed/exports.txt @@ -1,7 +1,4 @@ aligned_alloc -free -malloc -malloc_destructor sqlite3_anycollseq_init sqlite3_autovacuum_pages_go sqlite3_backup_finish @@ -9,7 +6,7 @@ sqlite3_backup_init sqlite3_backup_pagecount sqlite3_backup_remaining sqlite3_backup_step -sqlite3_bind_blob64 +sqlite3_bind_blob_go sqlite3_bind_double sqlite3_bind_int64 sqlite3_bind_null @@ -17,7 +14,7 @@ sqlite3_bind_parameter_count sqlite3_bind_parameter_index sqlite3_bind_parameter_name sqlite3_bind_pointer_go -sqlite3_bind_text64 +sqlite3_bind_text_go sqlite3_bind_value sqlite3_bind_zeroblob64 sqlite3_blob_bytes @@ -74,17 +71,20 @@ sqlite3_filename_database sqlite3_filename_journal sqlite3_filename_wal sqlite3_finalize +sqlite3_free sqlite3_get_autocommit sqlite3_get_auxdata sqlite3_interrupt sqlite3_last_insert_rowid sqlite3_limit +sqlite3_malloc64 sqlite3_open_v2 sqlite3_overload_function sqlite3_prepare_v3 sqlite3_progress_handler_go +sqlite3_realloc64 sqlite3_reset -sqlite3_result_blob64 +sqlite3_result_blob_go sqlite3_result_double sqlite3_result_error sqlite3_result_error_code @@ -93,7 +93,7 @@ sqlite3_result_error_toobig sqlite3_result_int64 sqlite3_result_null sqlite3_result_pointer_go -sqlite3_result_text64 +sqlite3_result_text_go sqlite3_result_value sqlite3_result_zeroblob64 sqlite3_rollback_hook_go diff --git a/embed/sqlite3.wasm b/embed/sqlite3.wasm index 353feac..8105ebb 100755 Binary files a/embed/sqlite3.wasm and b/embed/sqlite3.wasm differ diff --git a/go.work.sum b/go.work.sum index 76ac94b..085f015 100644 --- a/go.work.sum +++ b/go.work.sum @@ -5,5 +5,6 @@ golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= diff --git a/sqlite.go b/sqlite.go index 712ad51..1549ef9 100644 --- a/sqlite.go +++ b/sqlite.go @@ -86,7 +86,6 @@ type sqlite struct { mask uint32 } stack [9]uint64 - freer uint32 } func instantiateSQLite() (sqlt *sqlite, err error) { @@ -102,14 +101,7 @@ func instantiateSQLite() (sqlt *sqlite, err error) { if err != nil { return nil, err } - - global := sqlt.mod.ExportedGlobal("malloc_destructor") - if global == nil { - return nil, util.BadBinaryErr - } - - sqlt.freer = util.ReadUint32(sqlt.mod, uint32(global.Get())) - if sqlt.freer == 0 { + if sqlt.getfn("sqlite3_progress_handler_go") == nil { return nil, util.BadBinaryErr } return sqlt, nil @@ -196,15 +188,15 @@ func (sqlt *sqlite) free(ptr uint32) { if ptr == 0 { return } - sqlt.call("free", uint64(ptr)) + sqlt.call("sqlite3_free", uint64(ptr)) } func (sqlt *sqlite) new(size uint64) uint32 { - if size > _MAX_ALLOCATION_SIZE { - panic(util.OOMErr) + if size == 0 { + size = 1 } - ptr := uint32(sqlt.call("malloc", size)) - if ptr == 0 && size != 0 { + ptr := uint32(sqlt.call("sqlite3_malloc64", size)) + if ptr == 0 { panic(util.OOMErr) } return ptr diff --git a/sqlite3/bind.c b/sqlite3/bind.c new file mode 100644 index 0000000..254c232 --- /dev/null +++ b/sqlite3/bind.c @@ -0,0 +1,13 @@ +#include + +#include "sqlite3.h" + +int sqlite3_bind_text_go(sqlite3_stmt* stmt, int i, const char* zData, + sqlite3_uint64 nData) { + return sqlite3_bind_text64(stmt, i, zData, nData, &sqlite3_free, SQLITE_UTF8); +} + +int sqlite3_bind_blob_go(sqlite3_stmt* stmt, int i, const char* zData, + sqlite3_uint64 nData) { + return sqlite3_bind_blob64(stmt, i, zData, nData, &sqlite3_free); +} \ No newline at end of file diff --git a/sqlite3/main.c b/sqlite3/main.c index 4fb926b..50f10db 100644 --- a/sqlite3/main.c +++ b/sqlite3/main.c @@ -9,16 +9,16 @@ #include "ext/series.c" #include "ext/uint.c" // Bindings +#include "bind.c" #include "column.c" #include "func.c" #include "hooks.c" #include "pointer.c" +#include "result.c" #include "time.c" #include "vfs.c" #include "vtab.c" -sqlite3_destructor_type malloc_destructor = &free; - __attribute__((constructor)) void init() { sqlite3_initialize(); sqlite3_auto_extension((void (*)(void))sqlite3_base_init); diff --git a/sqlite3/result.c b/sqlite3/result.c new file mode 100644 index 0000000..6e79772 --- /dev/null +++ b/sqlite3/result.c @@ -0,0 +1,13 @@ +#include + +#include "sqlite3.h" + +void sqlite3_result_text_go(sqlite3_context* ctx, const char* zData, + sqlite3_uint64 nData) { + sqlite3_result_text64(ctx, zData, nData, &sqlite3_free, SQLITE_UTF8); +} + +void sqlite3_result_blob_go(sqlite3_context* ctx, const void* zData, + sqlite3_uint64 nData) { + sqlite3_result_blob64(ctx, zData, nData, &sqlite3_free); +} \ No newline at end of file diff --git a/sqlite_test.go b/sqlite_test.go index 88dc877..b5ce464 100644 --- a/sqlite_test.go +++ b/sqlite_test.go @@ -3,7 +3,6 @@ package sqlite3 import ( "bytes" "math" - "os" "testing" "github.com/ncruces/go-sqlite3/internal/util" @@ -39,7 +38,7 @@ func Test_sqlite_call_closed(t *testing.T) { sqlite.close() defer func() { _ = recover() }() - sqlite.call("free") + sqlite.call("sqlite3_free") t.Error("want panic") } @@ -57,19 +56,6 @@ func Test_sqlite_new(t *testing.T) { sqlite.new(math.MaxUint32) t.Error("want panic") }) - - t.Run("_MAX_ALLOCATION_SIZE", func(t *testing.T) { - if testing.Short() { - t.Skip("skipping in short mode") - } - if os.Getenv("CI") != "" { - t.Skip("skipping in CI") - } - defer func() { _ = recover() }() - sqlite.new(_MAX_ALLOCATION_SIZE) - sqlite.new(_MAX_ALLOCATION_SIZE) - t.Error("want panic") - }) } func Test_sqlite_newArena(t *testing.T) { diff --git a/stmt.go b/stmt.go index 8e6ad2c..e5d7246 100644 --- a/stmt.go +++ b/stmt.go @@ -246,10 +246,9 @@ func (s *Stmt) BindText(param int, value string) error { return TOOBIG } ptr := s.c.newString(value) - r := s.c.call("sqlite3_bind_text64", + r := s.c.call("sqlite3_bind_text_go", uint64(s.handle), uint64(param), - uint64(ptr), uint64(len(value)), - uint64(s.c.freer), _UTF8) + uint64(ptr), uint64(len(value))) return s.c.error(r) } @@ -262,10 +261,9 @@ func (s *Stmt) BindRawText(param int, value []byte) error { return TOOBIG } ptr := s.c.newBytes(value) - r := s.c.call("sqlite3_bind_text64", + r := s.c.call("sqlite3_bind_text_go", uint64(s.handle), uint64(param), - uint64(ptr), uint64(len(value)), - uint64(s.c.freer), _UTF8) + uint64(ptr), uint64(len(value))) return s.c.error(r) } @@ -279,10 +277,9 @@ func (s *Stmt) BindBlob(param int, value []byte) error { return TOOBIG } ptr := s.c.newBytes(value) - r := s.c.call("sqlite3_bind_blob64", + r := s.c.call("sqlite3_bind_blob_go", uint64(s.handle), uint64(param), - uint64(ptr), uint64(len(value)), - uint64(s.c.freer)) + uint64(ptr), uint64(len(value))) return s.c.error(r) } @@ -335,10 +332,9 @@ func (s *Stmt) bindRFC3339Nano(param int, value time.Time) error { buf := util.View(s.c.mod, ptr, maxlen) buf = value.AppendFormat(buf[:0], time.RFC3339Nano) - r := s.c.call("sqlite3_bind_text64", + r := s.c.call("sqlite3_bind_text_go", uint64(s.handle), uint64(param), - uint64(ptr), uint64(len(buf)), - uint64(s.c.freer), _UTF8) + uint64(ptr), uint64(len(buf))) return s.c.error(r) } diff --git a/vfs/vfs.go b/vfs/vfs.go index e0453fc..eb606bf 100644 --- a/vfs/vfs.go +++ b/vfs/vfs.go @@ -356,7 +356,7 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl out = err.Error() } if out != "" { - fn := mod.ExportedFunction("malloc") + fn := mod.ExportedFunction("sqlite3_malloc64") stack := [...]uint64{uint64(len(out) + 1)} if err := fn.CallWithStack(ctx, stack[:]); err != nil { panic(err)