mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
Memory management.
This commit is contained in:
11
const.go
11
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
|
||||
)
|
||||
|
||||
20
context.go
20
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],
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
|
||||
Binary file not shown.
@@ -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=
|
||||
|
||||
20
sqlite.go
20
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
|
||||
|
||||
13
sqlite3/bind.c
Normal file
13
sqlite3/bind.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
13
sqlite3/result.c
Normal file
13
sqlite3/result.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
20
stmt.go
20
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user