mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
Reentrant arenas.
This commit is contained in:
@@ -62,7 +62,7 @@ func (src *Conn) BackupInit(srcDB, dstURI string) (*Backup, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) backupInit(dst uint32, dstName string, src uint32, srcName string) (*Backup, error) {
|
func (c *Conn) backupInit(dst uint32, dstName string, src uint32, srcName string) (*Backup, error) {
|
||||||
defer c.arena.reset()
|
defer c.arena.mark()()
|
||||||
dstPtr := c.arena.string(dstName)
|
dstPtr := c.arena.string(dstName)
|
||||||
srcPtr := c.arena.string(srcName)
|
srcPtr := c.arena.string(srcName)
|
||||||
|
|
||||||
|
|||||||
18
blob.go
18
blob.go
@@ -30,7 +30,7 @@ var _ io.ReadWriteSeeker = &Blob{}
|
|||||||
// https://sqlite.org/c3ref/blob_open.html
|
// https://sqlite.org/c3ref/blob_open.html
|
||||||
func (c *Conn) OpenBlob(db, table, column string, row int64, write bool) (*Blob, error) {
|
func (c *Conn) OpenBlob(db, table, column string, row int64, write bool) (*Blob, error) {
|
||||||
c.checkInterrupt()
|
c.checkInterrupt()
|
||||||
defer c.arena.reset()
|
defer c.arena.mark()()
|
||||||
blobPtr := c.arena.new(ptrlen)
|
blobPtr := c.arena.new(ptrlen)
|
||||||
dbPtr := c.arena.string(db)
|
dbPtr := c.arena.string(db)
|
||||||
tablePtr := c.arena.string(table)
|
tablePtr := c.arena.string(table)
|
||||||
@@ -92,8 +92,8 @@ func (b *Blob) Read(p []byte) (n int, err error) {
|
|||||||
want = avail
|
want = avail
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr := b.c.new(uint64(want))
|
defer b.c.arena.mark()()
|
||||||
defer b.c.free(ptr)
|
ptr := b.c.arena.new(uint64(want))
|
||||||
|
|
||||||
r := b.c.call(b.c.api.blobRead, uint64(b.handle),
|
r := b.c.call(b.c.api.blobRead, uint64(b.handle),
|
||||||
uint64(ptr), uint64(want), uint64(b.offset))
|
uint64(ptr), uint64(want), uint64(b.offset))
|
||||||
@@ -124,8 +124,8 @@ func (b *Blob) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
want = avail
|
want = avail
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr := b.c.new(uint64(want))
|
defer b.c.arena.mark()()
|
||||||
defer b.c.free(ptr)
|
ptr := b.c.arena.new(uint64(want))
|
||||||
|
|
||||||
for want > 0 {
|
for want > 0 {
|
||||||
r := b.c.call(b.c.api.blobRead, uint64(b.handle),
|
r := b.c.call(b.c.api.blobRead, uint64(b.handle),
|
||||||
@@ -158,8 +158,8 @@ func (b *Blob) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
//
|
//
|
||||||
// https://sqlite.org/c3ref/blob_write.html
|
// https://sqlite.org/c3ref/blob_write.html
|
||||||
func (b *Blob) Write(p []byte) (n int, err error) {
|
func (b *Blob) Write(p []byte) (n int, err error) {
|
||||||
ptr := b.c.newBytes(p)
|
defer b.c.arena.mark()()
|
||||||
defer b.c.free(ptr)
|
ptr := b.c.arena.bytes(p)
|
||||||
|
|
||||||
r := b.c.call(b.c.api.blobWrite, uint64(b.handle),
|
r := b.c.call(b.c.api.blobWrite, uint64(b.handle),
|
||||||
uint64(ptr), uint64(len(p)), uint64(b.offset))
|
uint64(ptr), uint64(len(p)), uint64(b.offset))
|
||||||
@@ -187,8 +187,8 @@ func (b *Blob) ReadFrom(r io.Reader) (n int64, err error) {
|
|||||||
want = 1
|
want = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr := b.c.new(uint64(want))
|
defer b.c.arena.mark()()
|
||||||
defer b.c.free(ptr)
|
ptr := b.c.arena.new(uint64(want))
|
||||||
|
|
||||||
for {
|
for {
|
||||||
mem := util.View(b.c.mod, ptr, uint64(want))
|
mem := util.View(b.c.mod, ptr, uint64(want))
|
||||||
|
|||||||
9
conn.go
9
conn.go
@@ -72,7 +72,7 @@ func newConn(filename string, flags OpenFlag) (conn *Conn, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) {
|
func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) {
|
||||||
defer c.arena.reset()
|
defer c.arena.mark()()
|
||||||
connPtr := c.arena.new(ptrlen)
|
connPtr := c.arena.new(ptrlen)
|
||||||
namePtr := c.arena.string(filename)
|
namePtr := c.arena.string(filename)
|
||||||
|
|
||||||
@@ -96,7 +96,6 @@ func (c *Conn) openDB(filename string, flags OpenFlag) (uint32, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.arena.reset()
|
|
||||||
pragmaPtr := c.arena.string(pragmas.String())
|
pragmaPtr := c.arena.string(pragmas.String())
|
||||||
r := c.call(c.api.exec, uint64(handle), uint64(pragmaPtr), 0, 0, 0)
|
r := c.call(c.api.exec, uint64(handle), uint64(pragmaPtr), 0, 0, 0)
|
||||||
if err := c.sqlite.error(r, handle, pragmas.String()); err != nil {
|
if err := c.sqlite.error(r, handle, pragmas.String()); err != nil {
|
||||||
@@ -151,11 +150,11 @@ func (c *Conn) Close() error {
|
|||||||
// https://sqlite.org/c3ref/exec.html
|
// https://sqlite.org/c3ref/exec.html
|
||||||
func (c *Conn) Exec(sql string) error {
|
func (c *Conn) Exec(sql string) error {
|
||||||
c.checkInterrupt()
|
c.checkInterrupt()
|
||||||
defer c.arena.reset()
|
defer c.arena.mark()()
|
||||||
sqlPtr := c.arena.string(sql)
|
sqlPtr := c.arena.string(sql)
|
||||||
|
|
||||||
r := c.call(c.api.exec, uint64(c.handle), uint64(sqlPtr), 0, 0, 0)
|
r := c.call(c.api.exec, uint64(c.handle), uint64(sqlPtr), 0, 0, 0)
|
||||||
return c.error(r)
|
return c.error(r, sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare calls [Conn.PrepareFlags] with no flags.
|
// Prepare calls [Conn.PrepareFlags] with no flags.
|
||||||
@@ -177,7 +176,7 @@ func (c *Conn) PrepareFlags(sql string, flags PrepareFlag) (stmt *Stmt, tail str
|
|||||||
return nil, "", nil
|
return nil, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
defer c.arena.reset()
|
defer c.arena.mark()()
|
||||||
stmtPtr := c.arena.new(ptrlen)
|
stmtPtr := c.arena.new(ptrlen)
|
||||||
tailPtr := c.arena.new(ptrlen)
|
tailPtr := c.arena.new(ptrlen)
|
||||||
sqlPtr := c.arena.string(sql)
|
sqlPtr := c.arena.string(sql)
|
||||||
|
|||||||
@@ -208,10 +208,10 @@ func (ctx Context) ResultError(err error) {
|
|||||||
|
|
||||||
msg, code := errorCode(err, _OK)
|
msg, code := errorCode(err, _OK)
|
||||||
if msg != "" {
|
if msg != "" {
|
||||||
ptr := ctx.c.newString(msg)
|
defer ctx.c.arena.mark()()
|
||||||
|
ptr := ctx.c.arena.string(msg)
|
||||||
ctx.c.call(ctx.c.api.resultError,
|
ctx.c.call(ctx.c.api.resultError,
|
||||||
uint64(ctx.handle), uint64(ptr), uint64(len(msg)))
|
uint64(ctx.handle), uint64(ptr), uint64(len(msg)))
|
||||||
ctx.c.free(ptr)
|
|
||||||
}
|
}
|
||||||
if code != _OK {
|
if code != _OK {
|
||||||
ctx.c.call(ctx.c.api.resultErrorCode,
|
ctx.c.call(ctx.c.api.resultErrorCode,
|
||||||
|
|||||||
6
func.go
6
func.go
@@ -21,7 +21,7 @@ func (c *Conn) AnyCollationNeeded() {
|
|||||||
//
|
//
|
||||||
// https://sqlite.org/c3ref/create_collation.html
|
// https://sqlite.org/c3ref/create_collation.html
|
||||||
func (c *Conn) CreateCollation(name string, fn func(a, b []byte) int) error {
|
func (c *Conn) CreateCollation(name string, fn func(a, b []byte) int) error {
|
||||||
defer c.arena.reset()
|
defer c.arena.mark()()
|
||||||
namePtr := c.arena.string(name)
|
namePtr := c.arena.string(name)
|
||||||
funcPtr := util.AddHandle(c.ctx, fn)
|
funcPtr := util.AddHandle(c.ctx, fn)
|
||||||
r := c.call(c.api.createCollation,
|
r := c.call(c.api.createCollation,
|
||||||
@@ -33,7 +33,7 @@ func (c *Conn) CreateCollation(name string, fn func(a, b []byte) int) error {
|
|||||||
//
|
//
|
||||||
// https://sqlite.org/c3ref/create_function.html
|
// https://sqlite.org/c3ref/create_function.html
|
||||||
func (c *Conn) CreateFunction(name string, nArg int, flag FunctionFlag, fn func(ctx Context, arg ...Value)) error {
|
func (c *Conn) CreateFunction(name string, nArg int, flag FunctionFlag, fn func(ctx Context, arg ...Value)) error {
|
||||||
defer c.arena.reset()
|
defer c.arena.mark()()
|
||||||
namePtr := c.arena.string(name)
|
namePtr := c.arena.string(name)
|
||||||
funcPtr := util.AddHandle(c.ctx, fn)
|
funcPtr := util.AddHandle(c.ctx, fn)
|
||||||
r := c.call(c.api.createFunction,
|
r := c.call(c.api.createFunction,
|
||||||
@@ -48,7 +48,7 @@ func (c *Conn) CreateFunction(name string, nArg int, flag FunctionFlag, fn func(
|
|||||||
//
|
//
|
||||||
// https://sqlite.org/c3ref/create_function.html
|
// https://sqlite.org/c3ref/create_function.html
|
||||||
func (c *Conn) CreateWindowFunction(name string, nArg int, flag FunctionFlag, fn func() AggregateFunction) error {
|
func (c *Conn) CreateWindowFunction(name string, nArg int, flag FunctionFlag, fn func() AggregateFunction) error {
|
||||||
defer c.arena.reset()
|
defer c.arena.mark()()
|
||||||
call := c.api.createAggregate
|
call := c.api.createAggregate
|
||||||
namePtr := c.arena.string(name)
|
namePtr := c.arena.string(name)
|
||||||
funcPtr := util.AddHandle(c.ctx, fn)
|
funcPtr := util.AddHandle(c.ctx, fn)
|
||||||
|
|||||||
18
sqlite.go
18
sqlite.go
@@ -294,17 +294,23 @@ func (a *arena) free() {
|
|||||||
if a.sqlt == nil {
|
if a.sqlt == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
a.reset()
|
for _, ptr := range a.ptrs {
|
||||||
|
a.sqlt.free(ptr)
|
||||||
|
}
|
||||||
a.sqlt.free(a.base)
|
a.sqlt.free(a.base)
|
||||||
a.sqlt = nil
|
a.sqlt = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *arena) reset() {
|
func (a *arena) mark() (reset func()) {
|
||||||
for _, ptr := range a.ptrs {
|
ptrs := len(a.ptrs)
|
||||||
a.sqlt.free(ptr)
|
next := a.next
|
||||||
|
return func() {
|
||||||
|
for _, ptr := range a.ptrs[ptrs:] {
|
||||||
|
a.sqlt.free(ptr)
|
||||||
|
}
|
||||||
|
a.ptrs = a.ptrs[:ptrs]
|
||||||
|
a.next = next
|
||||||
}
|
}
|
||||||
a.ptrs = nil
|
|
||||||
a.next = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *arena) new(size uint64) uint32 {
|
func (a *arena) new(size uint64) uint32 {
|
||||||
|
|||||||
2
stmt.go
2
stmt.go
@@ -104,7 +104,7 @@ func (s *Stmt) BindCount() int {
|
|||||||
//
|
//
|
||||||
// https://sqlite.org/c3ref/bind_parameter_index.html
|
// https://sqlite.org/c3ref/bind_parameter_index.html
|
||||||
func (s *Stmt) BindIndex(name string) int {
|
func (s *Stmt) BindIndex(name string) int {
|
||||||
defer s.c.arena.reset()
|
defer s.c.arena.mark()()
|
||||||
namePtr := s.c.arena.string(name)
|
namePtr := s.c.arena.string(name)
|
||||||
r := s.c.call(s.c.api.bindIndex,
|
r := s.c.call(s.c.api.bindIndex,
|
||||||
uint64(s.handle), uint64(namePtr))
|
uint64(s.handle), uint64(namePtr))
|
||||||
|
|||||||
15
vtab.go
15
vtab.go
@@ -53,7 +53,7 @@ func CreateModule[T VTab](db *Conn, name string, create, connect VTabConstructor
|
|||||||
flags |= VTAB_SAVEPOINTER
|
flags |= VTAB_SAVEPOINTER
|
||||||
}
|
}
|
||||||
|
|
||||||
defer db.arena.reset()
|
defer db.arena.mark()()
|
||||||
namePtr := db.arena.string(name)
|
namePtr := db.arena.string(name)
|
||||||
modulePtr := util.AddHandle(db.ctx, module[T]{create, connect})
|
modulePtr := util.AddHandle(db.ctx, module[T]{create, connect})
|
||||||
r := db.call(db.api.createModule, uint64(db.handle),
|
r := db.call(db.api.createModule, uint64(db.handle),
|
||||||
@@ -70,7 +70,7 @@ func implements[T any](typ reflect.Type) bool {
|
|||||||
//
|
//
|
||||||
// https://sqlite.org/c3ref/declare_vtab.html
|
// https://sqlite.org/c3ref/declare_vtab.html
|
||||||
func (c *Conn) DeclareVtab(sql string) error {
|
func (c *Conn) DeclareVtab(sql string) error {
|
||||||
// The arena will be cleared by the prepare or exec method.
|
defer c.arena.mark()()
|
||||||
sqlPtr := c.arena.string(sql)
|
sqlPtr := c.arena.string(sql)
|
||||||
r := c.call(c.api.declareVTab, uint64(c.handle), uint64(sqlPtr))
|
r := c.call(c.api.declareVTab, uint64(c.handle), uint64(sqlPtr))
|
||||||
return c.error(r)
|
return c.error(r)
|
||||||
@@ -255,7 +255,7 @@ type IndexConstraintUsage struct {
|
|||||||
//
|
//
|
||||||
// https://sqlite.org/c3ref/vtab_rhs_value.html
|
// https://sqlite.org/c3ref/vtab_rhs_value.html
|
||||||
func (idx *IndexInfo) RHSValue(column int) (*Value, error) {
|
func (idx *IndexInfo) RHSValue(column int) (*Value, error) {
|
||||||
// The arena will be cleared by the prepare or exec method.
|
defer idx.c.arena.mark()()
|
||||||
valPtr := idx.c.arena.new(ptrlen)
|
valPtr := idx.c.arena.new(ptrlen)
|
||||||
r := idx.c.call(idx.c.api.vtabRHSValue,
|
r := idx.c.call(idx.c.api.vtabRHSValue,
|
||||||
uint64(idx.handle), uint64(column), uint64(valPtr))
|
uint64(idx.handle), uint64(column), uint64(valPtr))
|
||||||
@@ -318,7 +318,7 @@ func (idx *IndexInfo) save() {
|
|||||||
util.WriteUint32(mod, ptr+20, uint32(idx.IdxNum))
|
util.WriteUint32(mod, ptr+20, uint32(idx.IdxNum))
|
||||||
if idx.IdxStr != "" {
|
if idx.IdxStr != "" {
|
||||||
util.WriteUint32(mod, ptr+24, idx.c.newString(idx.IdxStr))
|
util.WriteUint32(mod, ptr+24, idx.c.newString(idx.IdxStr))
|
||||||
util.WriteUint32(mod, ptr+28, 1)
|
util.WriteUint32(mod, ptr+28, 1) // needToFreeIdxStr
|
||||||
}
|
}
|
||||||
if idx.OrderByConsumed {
|
if idx.OrderByConsumed {
|
||||||
util.WriteUint32(mod, ptr+32, 1)
|
util.WriteUint32(mod, ptr+32, 1)
|
||||||
@@ -567,11 +567,14 @@ func vtabError(ctx context.Context, mod api.Module, ptr, kind uint32, err error)
|
|||||||
if msg != "" && ptr != 0 {
|
if msg != "" && ptr != 0 {
|
||||||
switch kind {
|
switch kind {
|
||||||
case _VTAB_ERROR:
|
case _VTAB_ERROR:
|
||||||
ptr = ptr + 8
|
ptr = ptr + 8 // zErrMsg
|
||||||
case _CURSOR_ERROR:
|
case _CURSOR_ERROR:
|
||||||
ptr = util.ReadUint32(mod, ptr) + 8
|
ptr = util.ReadUint32(mod, ptr) + 8 // pVtab->zErrMsg
|
||||||
}
|
}
|
||||||
db := ctx.Value(connKey{}).(*Conn)
|
db := ctx.Value(connKey{}).(*Conn)
|
||||||
|
if ptr := util.ReadUint32(mod, ptr); ptr != 0 {
|
||||||
|
db.free(ptr)
|
||||||
|
}
|
||||||
util.WriteUint32(mod, ptr, db.newString(msg))
|
util.WriteUint32(mod, ptr, db.newString(msg))
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
|
|||||||
Reference in New Issue
Block a user