[chore] Update go-sqlite3 to 0.18.3 (#3295)
* [chore] Update go-sqlite3 to 0.18.3 * [chore] Fix getting the sqlite3.Conn
This commit is contained in:
parent
486852fb38
commit
4fa0d41202
2
go.mod
2
go.mod
|
@ -44,7 +44,7 @@ require (
|
||||||
github.com/miekg/dns v1.1.62
|
github.com/miekg/dns v1.1.62
|
||||||
github.com/minio/minio-go/v7 v7.0.76
|
github.com/minio/minio-go/v7 v7.0.76
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/ncruces/go-sqlite3 v0.18.1
|
github.com/ncruces/go-sqlite3 v0.18.3
|
||||||
github.com/oklog/ulid v1.3.1
|
github.com/oklog/ulid v1.3.1
|
||||||
github.com/prometheus/client_golang v1.20.3
|
github.com/prometheus/client_golang v1.20.3
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/spf13/cobra v1.8.1
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -440,8 +440,8 @@ github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=
|
||||||
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/ncruces/go-sqlite3 v0.18.1 h1:iN8IMZV5EMxpH88NUac9vId23eTKNFUhP7jgY0EBbNc=
|
github.com/ncruces/go-sqlite3 v0.18.3 h1:tyMa75uh7LcINcfo0WrzOvcTkfz8Hqu0TEPX+KVyes4=
|
||||||
github.com/ncruces/go-sqlite3 v0.18.1/go.mod h1:eEOyZnW1dGTJ+zDpMuzfYamEUBtdFz5zeYhqLBtHxvM=
|
github.com/ncruces/go-sqlite3 v0.18.3/go.mod h1:HAwOtA+cyEX3iN6YmkpQwfT4vMMgCB7rQRFUdOgEFik=
|
||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
|
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
|
||||||
|
|
|
@ -25,7 +25,6 @@ import (
|
||||||
|
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
|
|
||||||
"github.com/ncruces/go-sqlite3"
|
|
||||||
sqlite3driver "github.com/ncruces/go-sqlite3/driver"
|
sqlite3driver "github.com/ncruces/go-sqlite3/driver"
|
||||||
_ "github.com/ncruces/go-sqlite3/embed" // embed wasm binary
|
_ "github.com/ncruces/go-sqlite3/embed" // embed wasm binary
|
||||||
_ "github.com/ncruces/go-sqlite3/vfs/memdb" // include memdb vfs
|
_ "github.com/ncruces/go-sqlite3/vfs/memdb" // include memdb vfs
|
||||||
|
@ -110,7 +109,7 @@ func (c *sqliteConn) ExecContext(ctx context.Context, query string, args []drive
|
||||||
|
|
||||||
func (c *sqliteConn) Close() (err error) {
|
func (c *sqliteConn) Close() (err error) {
|
||||||
// Get acces the underlying raw sqlite3 conn.
|
// Get acces the underlying raw sqlite3 conn.
|
||||||
raw := c.connIface.(sqlite3.DriverConn).Raw()
|
raw := c.connIface.(sqlite3driver.Conn).Raw()
|
||||||
|
|
||||||
// see: https://www.sqlite.org/pragma.html#pragma_optimize
|
// see: https://www.sqlite.org/pragma.html#pragma_optimize
|
||||||
const onClose = "PRAGMA analysis_limit=1000; PRAGMA optimize;"
|
const onClose = "PRAGMA analysis_limit=1000; PRAGMA optimize;"
|
||||||
|
|
|
@ -21,6 +21,8 @@ type Blob struct {
|
||||||
bytes int64
|
bytes int64
|
||||||
offset int64
|
offset int64
|
||||||
handle uint32
|
handle uint32
|
||||||
|
bufptr uint32
|
||||||
|
buflen int64
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ io.ReadWriteSeeker = &Blob{}
|
var _ io.ReadWriteSeeker = &Blob{}
|
||||||
|
@ -66,7 +68,7 @@ func (b *Blob) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
r := b.c.call("sqlite3_blob_close", uint64(b.handle))
|
r := b.c.call("sqlite3_blob_close", uint64(b.handle))
|
||||||
|
b.c.free(b.bufptr)
|
||||||
b.handle = 0
|
b.handle = 0
|
||||||
return b.c.error(r)
|
return b.c.error(r)
|
||||||
}
|
}
|
||||||
|
@ -86,17 +88,18 @@ func (b *Blob) Read(p []byte) (n int, err error) {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
avail := b.bytes - b.offset
|
|
||||||
want := int64(len(p))
|
want := int64(len(p))
|
||||||
|
avail := b.bytes - b.offset
|
||||||
if want > avail {
|
if want > avail {
|
||||||
want = avail
|
want = avail
|
||||||
}
|
}
|
||||||
|
if want > b.buflen {
|
||||||
defer b.c.arena.mark()()
|
b.bufptr = b.c.realloc(b.bufptr, uint64(want))
|
||||||
ptr := b.c.arena.new(uint64(want))
|
b.buflen = want
|
||||||
|
}
|
||||||
|
|
||||||
r := b.c.call("sqlite3_blob_read", uint64(b.handle),
|
r := b.c.call("sqlite3_blob_read", uint64(b.handle),
|
||||||
uint64(ptr), uint64(want), uint64(b.offset))
|
uint64(b.bufptr), uint64(want), uint64(b.offset))
|
||||||
err = b.c.error(r)
|
err = b.c.error(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
@ -106,7 +109,7 @@ func (b *Blob) Read(p []byte) (n int, err error) {
|
||||||
err = io.EOF
|
err = io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(p, util.View(b.c.mod, ptr, uint64(want)))
|
copy(p, util.View(b.c.mod, b.bufptr, uint64(want)))
|
||||||
return int(want), err
|
return int(want), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,19 +126,20 @@ func (b *Blob) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
if want > avail {
|
if want > avail {
|
||||||
want = avail
|
want = avail
|
||||||
}
|
}
|
||||||
|
if want > b.buflen {
|
||||||
defer b.c.arena.mark()()
|
b.bufptr = b.c.realloc(b.bufptr, uint64(want))
|
||||||
ptr := b.c.arena.new(uint64(want))
|
b.buflen = want
|
||||||
|
}
|
||||||
|
|
||||||
for want > 0 {
|
for want > 0 {
|
||||||
r := b.c.call("sqlite3_blob_read", uint64(b.handle),
|
r := b.c.call("sqlite3_blob_read", uint64(b.handle),
|
||||||
uint64(ptr), uint64(want), uint64(b.offset))
|
uint64(b.bufptr), uint64(want), uint64(b.offset))
|
||||||
err = b.c.error(r)
|
err = b.c.error(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mem := util.View(b.c.mod, ptr, uint64(want))
|
mem := util.View(b.c.mod, b.bufptr, uint64(want))
|
||||||
m, err := w.Write(mem[:want])
|
m, err := w.Write(mem[:want])
|
||||||
b.offset += int64(m)
|
b.offset += int64(m)
|
||||||
n += int64(m)
|
n += int64(m)
|
||||||
|
@ -159,11 +163,15 @@ 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) {
|
||||||
defer b.c.arena.mark()()
|
want := int64(len(p))
|
||||||
ptr := b.c.arena.bytes(p)
|
if want > b.buflen {
|
||||||
|
b.bufptr = b.c.realloc(b.bufptr, uint64(want))
|
||||||
|
b.buflen = want
|
||||||
|
}
|
||||||
|
util.WriteBytes(b.c.mod, b.bufptr, p)
|
||||||
|
|
||||||
r := b.c.call("sqlite3_blob_write", uint64(b.handle),
|
r := b.c.call("sqlite3_blob_write", uint64(b.handle),
|
||||||
uint64(ptr), uint64(len(p)), uint64(b.offset))
|
uint64(b.bufptr), uint64(want), uint64(b.offset))
|
||||||
err = b.c.error(r)
|
err = b.c.error(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
@ -187,16 +195,17 @@ func (b *Blob) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
if want < 1 {
|
if want < 1 {
|
||||||
want = 1
|
want = 1
|
||||||
}
|
}
|
||||||
|
if want > b.buflen {
|
||||||
defer b.c.arena.mark()()
|
b.bufptr = b.c.realloc(b.bufptr, uint64(want))
|
||||||
ptr := b.c.arena.new(uint64(want))
|
b.buflen = want
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
mem := util.View(b.c.mod, ptr, uint64(want))
|
mem := util.View(b.c.mod, b.bufptr, uint64(want))
|
||||||
m, err := r.Read(mem[:want])
|
m, err := r.Read(mem[:want])
|
||||||
if m > 0 {
|
if m > 0 {
|
||||||
r := b.c.call("sqlite3_blob_write", uint64(b.handle),
|
r := b.c.call("sqlite3_blob_write", uint64(b.handle),
|
||||||
uint64(ptr), uint64(m), uint64(b.offset))
|
uint64(b.bufptr), uint64(m), uint64(b.offset))
|
||||||
err := b.c.error(r)
|
err := b.c.error(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
|
|
|
@ -294,3 +294,17 @@ func autoVacuumCallback(ctx context.Context, mod api.Module, pApp, zSchema, nDbP
|
||||||
schema := util.ReadString(mod, zSchema, _MAX_NAME)
|
schema := util.ReadString(mod, zSchema, _MAX_NAME)
|
||||||
return uint32(fn(schema, uint(nDbPage), uint(nFreePage), uint(nBytePerPage)))
|
return uint32(fn(schema, uint(nDbPage), uint(nFreePage), uint(nBytePerPage)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SoftHeapLimit imposes a soft limit on heap size.
|
||||||
|
//
|
||||||
|
// https://sqlite.org/c3ref/hard_heap_limit64.html
|
||||||
|
func (c *Conn) SoftHeapLimit(n int64) int64 {
|
||||||
|
return int64(c.call("sqlite3_soft_heap_limit64", uint64(n)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SoftHeapLimit imposes a hard limit on heap size.
|
||||||
|
//
|
||||||
|
// https://sqlite.org/c3ref/hard_heap_limit64.html
|
||||||
|
func (c *Conn) HardHeapLimit(n int64) int64 {
|
||||||
|
return int64(c.call("sqlite3_hard_heap_limit64", uint64(n)))
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ type Conn struct {
|
||||||
interrupt context.Context
|
interrupt context.Context
|
||||||
pending *Stmt
|
pending *Stmt
|
||||||
stmts []*Stmt
|
stmts []*Stmt
|
||||||
|
timer *time.Timer
|
||||||
busy func(int) bool
|
busy func(int) bool
|
||||||
log func(xErrorCode, string)
|
log func(xErrorCode, string)
|
||||||
collation func(*Conn, string)
|
collation func(*Conn, string)
|
||||||
|
@ -389,11 +390,25 @@ func timeoutCallback(ctx context.Context, mod api.Module, pDB uint32, count, tmo
|
||||||
}
|
}
|
||||||
|
|
||||||
if delay = min(delay, tmout-prior); delay > 0 {
|
if delay = min(delay, tmout-prior); delay > 0 {
|
||||||
time.Sleep(time.Duration(delay) * time.Millisecond)
|
delay := time.Duration(delay) * time.Millisecond
|
||||||
retry = 1
|
if c.interrupt == nil || c.interrupt.Done() == nil {
|
||||||
|
time.Sleep(delay)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if c.timer == nil {
|
||||||
|
c.timer = time.NewTimer(delay)
|
||||||
|
} else {
|
||||||
|
c.timer.Reset(delay)
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-c.interrupt.Done():
|
||||||
|
c.timer.Stop()
|
||||||
|
case <-c.timer.C:
|
||||||
|
return 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return retry
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// BusyHandler registers a callback to handle [BUSY] errors.
|
// BusyHandler registers a callback to handle [BUSY] errors.
|
||||||
|
@ -492,9 +507,7 @@ func (c *Conn) stmtsIter(yield func(*Stmt) bool) {
|
||||||
|
|
||||||
// DriverConn is implemented by the SQLite [database/sql] driver connection.
|
// DriverConn is implemented by the SQLite [database/sql] driver connection.
|
||||||
//
|
//
|
||||||
// It can be used to access SQLite features like [online backup].
|
// Deprecated: use [github.com/ncruces/go-sqlite3/driver.Conn] instead.
|
||||||
//
|
|
||||||
// [online backup]: https://sqlite.org/backup.html
|
|
||||||
type DriverConn interface {
|
type DriverConn interface {
|
||||||
Raw() *Conn
|
Raw() *Conn
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,10 @@ const (
|
||||||
_ROW = 100 /* sqlite3_step() has another row ready */
|
_ROW = 100 /* sqlite3_step() has another row ready */
|
||||||
_DONE = 101 /* sqlite3_step() has finished executing */
|
_DONE = 101 /* sqlite3_step() has finished executing */
|
||||||
|
|
||||||
_UTF8 = 1
|
_MAX_NAME = 1e6 // Self-imposed limit for most NUL terminated strings.
|
||||||
|
_MAX_LENGTH = 1e9
|
||||||
_MAX_NAME = 1e6 // Self-imposed limit for most NUL terminated strings.
|
_MAX_SQL_LENGTH = 1e9
|
||||||
_MAX_LENGTH = 1e9
|
_MAX_FUNCTION_ARG = 100
|
||||||
_MAX_SQL_LENGTH = 1e9
|
|
||||||
_MAX_ALLOCATION_SIZE = 0x7ffffeff
|
|
||||||
_MAX_FUNCTION_ARG = 100
|
|
||||||
|
|
||||||
ptrlen = 4
|
ptrlen = 4
|
||||||
)
|
)
|
||||||
|
|
|
@ -84,9 +84,8 @@ func (ctx Context) ResultFloat(value float64) {
|
||||||
// https://sqlite.org/c3ref/result_blob.html
|
// https://sqlite.org/c3ref/result_blob.html
|
||||||
func (ctx Context) ResultText(value string) {
|
func (ctx Context) ResultText(value string) {
|
||||||
ptr := ctx.c.newString(value)
|
ptr := ctx.c.newString(value)
|
||||||
ctx.c.call("sqlite3_result_text64",
|
ctx.c.call("sqlite3_result_text_go",
|
||||||
uint64(ctx.handle), uint64(ptr), uint64(len(value)),
|
uint64(ctx.handle), uint64(ptr), uint64(len(value)))
|
||||||
uint64(ctx.c.freer), _UTF8)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResultRawText sets the text result of the function to a []byte.
|
// 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
|
// https://sqlite.org/c3ref/result_blob.html
|
||||||
func (ctx Context) ResultRawText(value []byte) {
|
func (ctx Context) ResultRawText(value []byte) {
|
||||||
ptr := ctx.c.newBytes(value)
|
ptr := ctx.c.newBytes(value)
|
||||||
ctx.c.call("sqlite3_result_text64",
|
ctx.c.call("sqlite3_result_text_go",
|
||||||
uint64(ctx.handle), uint64(ptr), uint64(len(value)),
|
uint64(ctx.handle), uint64(ptr), uint64(len(value)))
|
||||||
uint64(ctx.c.freer), _UTF8)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResultBlob sets the result of the function to a []byte.
|
// 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
|
// https://sqlite.org/c3ref/result_blob.html
|
||||||
func (ctx Context) ResultBlob(value []byte) {
|
func (ctx Context) ResultBlob(value []byte) {
|
||||||
ptr := ctx.c.newBytes(value)
|
ptr := ctx.c.newBytes(value)
|
||||||
ctx.c.call("sqlite3_result_blob64",
|
ctx.c.call("sqlite3_result_blob_go",
|
||||||
uint64(ctx.handle), uint64(ptr), uint64(len(value)),
|
uint64(ctx.handle), uint64(ptr), uint64(len(value)))
|
||||||
uint64(ctx.c.freer))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResultZeroBlob sets the result of the function to a zero-filled, length n BLOB.
|
// 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 := util.View(ctx.c.mod, ptr, maxlen)
|
||||||
buf = value.AppendFormat(buf[:0], time.RFC3339Nano)
|
buf = value.AppendFormat(buf[:0], time.RFC3339Nano)
|
||||||
|
|
||||||
ctx.c.call("sqlite3_result_text64",
|
ctx.c.call("sqlite3_result_text_go",
|
||||||
uint64(ctx.handle), uint64(ptr), uint64(len(buf)),
|
uint64(ctx.handle), uint64(ptr), uint64(len(buf)))
|
||||||
uint64(ctx.c.freer), _UTF8)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResultPointer sets the result of the function to NULL, just like [Context.ResultNull],
|
// ResultPointer sets the result of the function to NULL, just like [Context.ResultNull],
|
||||||
|
|
|
@ -130,6 +130,11 @@ type SQLite struct {
|
||||||
term func(*sqlite3.Conn) error
|
term func(*sqlite3.Conn) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Ensure these interfaces are implemented:
|
||||||
|
_ driver.DriverContext = &SQLite{}
|
||||||
|
)
|
||||||
|
|
||||||
// Open implements [database/sql/driver.Driver].
|
// Open implements [database/sql/driver.Driver].
|
||||||
func (d *SQLite) Open(name string) (driver.Conn, error) {
|
func (d *SQLite) Open(name string) (driver.Conn, error) {
|
||||||
c, err := d.newConnector(name)
|
c, err := d.newConnector(name)
|
||||||
|
@ -255,6 +260,35 @@ func (n *connector) Connect(ctx context.Context) (_ driver.Conn, err error) {
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Conn is implemented by the SQLite [database/sql] driver connections.
|
||||||
|
//
|
||||||
|
// It can be used to access SQLite features like [online backup]:
|
||||||
|
//
|
||||||
|
// db, err := driver.Open("temp.db")
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
// defer db.Close()
|
||||||
|
//
|
||||||
|
// conn, err := db.Conn(context.TODO())
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// err = conn.Raw(func(driverConn any) error {
|
||||||
|
// conn := driverConn.(driver.Conn)
|
||||||
|
// return conn.Raw().Backup("main", "backup.db")
|
||||||
|
// })
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// [online backup]: https://sqlite.org/backup.html
|
||||||
|
type Conn interface {
|
||||||
|
Raw() *sqlite3.Conn
|
||||||
|
driver.Conn
|
||||||
|
}
|
||||||
|
|
||||||
type conn struct {
|
type conn struct {
|
||||||
*sqlite3.Conn
|
*sqlite3.Conn
|
||||||
txLock string
|
txLock string
|
||||||
|
@ -266,10 +300,10 @@ type conn struct {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Ensure these interfaces are implemented:
|
// Ensure these interfaces are implemented:
|
||||||
|
_ Conn = &conn{}
|
||||||
|
_ driver.ConnBeginTx = &conn{}
|
||||||
_ driver.ConnPrepareContext = &conn{}
|
_ driver.ConnPrepareContext = &conn{}
|
||||||
_ driver.ExecerContext = &conn{}
|
_ driver.ExecerContext = &conn{}
|
||||||
_ driver.ConnBeginTx = &conn{}
|
|
||||||
_ sqlite3.DriverConn = &conn{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *conn) Raw() *sqlite3.Conn {
|
func (c *conn) Raw() *sqlite3.Conn {
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
aligned_alloc
|
aligned_alloc
|
||||||
free
|
|
||||||
malloc
|
|
||||||
malloc_destructor
|
|
||||||
sqlite3_anycollseq_init
|
sqlite3_anycollseq_init
|
||||||
sqlite3_autovacuum_pages_go
|
sqlite3_autovacuum_pages_go
|
||||||
sqlite3_backup_finish
|
sqlite3_backup_finish
|
||||||
|
@ -9,7 +6,7 @@ sqlite3_backup_init
|
||||||
sqlite3_backup_pagecount
|
sqlite3_backup_pagecount
|
||||||
sqlite3_backup_remaining
|
sqlite3_backup_remaining
|
||||||
sqlite3_backup_step
|
sqlite3_backup_step
|
||||||
sqlite3_bind_blob64
|
sqlite3_bind_blob_go
|
||||||
sqlite3_bind_double
|
sqlite3_bind_double
|
||||||
sqlite3_bind_int64
|
sqlite3_bind_int64
|
||||||
sqlite3_bind_null
|
sqlite3_bind_null
|
||||||
|
@ -17,7 +14,7 @@ sqlite3_bind_parameter_count
|
||||||
sqlite3_bind_parameter_index
|
sqlite3_bind_parameter_index
|
||||||
sqlite3_bind_parameter_name
|
sqlite3_bind_parameter_name
|
||||||
sqlite3_bind_pointer_go
|
sqlite3_bind_pointer_go
|
||||||
sqlite3_bind_text64
|
sqlite3_bind_text_go
|
||||||
sqlite3_bind_value
|
sqlite3_bind_value
|
||||||
sqlite3_bind_zeroblob64
|
sqlite3_bind_zeroblob64
|
||||||
sqlite3_blob_bytes
|
sqlite3_blob_bytes
|
||||||
|
@ -74,17 +71,21 @@ sqlite3_filename_database
|
||||||
sqlite3_filename_journal
|
sqlite3_filename_journal
|
||||||
sqlite3_filename_wal
|
sqlite3_filename_wal
|
||||||
sqlite3_finalize
|
sqlite3_finalize
|
||||||
|
sqlite3_free
|
||||||
sqlite3_get_autocommit
|
sqlite3_get_autocommit
|
||||||
sqlite3_get_auxdata
|
sqlite3_get_auxdata
|
||||||
|
sqlite3_hard_heap_limit64
|
||||||
sqlite3_interrupt
|
sqlite3_interrupt
|
||||||
sqlite3_last_insert_rowid
|
sqlite3_last_insert_rowid
|
||||||
sqlite3_limit
|
sqlite3_limit
|
||||||
|
sqlite3_malloc64
|
||||||
sqlite3_open_v2
|
sqlite3_open_v2
|
||||||
sqlite3_overload_function
|
sqlite3_overload_function
|
||||||
sqlite3_prepare_v3
|
sqlite3_prepare_v3
|
||||||
sqlite3_progress_handler_go
|
sqlite3_progress_handler_go
|
||||||
|
sqlite3_realloc64
|
||||||
sqlite3_reset
|
sqlite3_reset
|
||||||
sqlite3_result_blob64
|
sqlite3_result_blob_go
|
||||||
sqlite3_result_double
|
sqlite3_result_double
|
||||||
sqlite3_result_error
|
sqlite3_result_error
|
||||||
sqlite3_result_error_code
|
sqlite3_result_error_code
|
||||||
|
@ -93,13 +94,14 @@ sqlite3_result_error_toobig
|
||||||
sqlite3_result_int64
|
sqlite3_result_int64
|
||||||
sqlite3_result_null
|
sqlite3_result_null
|
||||||
sqlite3_result_pointer_go
|
sqlite3_result_pointer_go
|
||||||
sqlite3_result_text64
|
sqlite3_result_text_go
|
||||||
sqlite3_result_value
|
sqlite3_result_value
|
||||||
sqlite3_result_zeroblob64
|
sqlite3_result_zeroblob64
|
||||||
sqlite3_rollback_hook_go
|
sqlite3_rollback_hook_go
|
||||||
sqlite3_set_authorizer_go
|
sqlite3_set_authorizer_go
|
||||||
sqlite3_set_auxdata_go
|
sqlite3_set_auxdata_go
|
||||||
sqlite3_set_last_insert_rowid
|
sqlite3_set_last_insert_rowid
|
||||||
|
sqlite3_soft_heap_limit64
|
||||||
sqlite3_step
|
sqlite3_step
|
||||||
sqlite3_stmt_busy
|
sqlite3_stmt_busy
|
||||||
sqlite3_stmt_readonly
|
sqlite3_stmt_readonly
|
||||||
|
|
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.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||||
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
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.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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
|
|
|
@ -39,7 +39,7 @@ type mmappedMemory struct {
|
||||||
func (m *mmappedMemory) Reallocate(size uint64) []byte {
|
func (m *mmappedMemory) Reallocate(size uint64) []byte {
|
||||||
com := uint64(len(m.buf))
|
com := uint64(len(m.buf))
|
||||||
res := uint64(cap(m.buf))
|
res := uint64(cap(m.buf))
|
||||||
if com < size && size < res {
|
if com < size && size <= res {
|
||||||
// Round up to the page size.
|
// Round up to the page size.
|
||||||
rnd := uint64(unix.Getpagesize() - 1)
|
rnd := uint64(unix.Getpagesize() - 1)
|
||||||
new := (size + rnd) &^ rnd
|
new := (size + rnd) &^ rnd
|
||||||
|
|
|
@ -48,7 +48,7 @@ type virtualMemory struct {
|
||||||
func (m *virtualMemory) Reallocate(size uint64) []byte {
|
func (m *virtualMemory) Reallocate(size uint64) []byte {
|
||||||
com := uint64(len(m.buf))
|
com := uint64(len(m.buf))
|
||||||
res := uint64(cap(m.buf))
|
res := uint64(cap(m.buf))
|
||||||
if com < size && size < res {
|
if com < size && size <= res {
|
||||||
// Round up to the page size.
|
// Round up to the page size.
|
||||||
rnd := uint64(windows.Getpagesize() - 1)
|
rnd := uint64(windows.Getpagesize() - 1)
|
||||||
new := (size + rnd) &^ rnd
|
new := (size + rnd) &^ rnd
|
||||||
|
|
|
@ -86,7 +86,6 @@ type sqlite struct {
|
||||||
mask uint32
|
mask uint32
|
||||||
}
|
}
|
||||||
stack [9]uint64
|
stack [9]uint64
|
||||||
freer uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func instantiateSQLite() (sqlt *sqlite, err error) {
|
func instantiateSQLite() (sqlt *sqlite, err error) {
|
||||||
|
@ -102,14 +101,7 @@ func instantiateSQLite() (sqlt *sqlite, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if sqlt.getfn("sqlite3_progress_handler_go") == nil {
|
||||||
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 {
|
|
||||||
return nil, util.BadBinaryErr
|
return nil, util.BadBinaryErr
|
||||||
}
|
}
|
||||||
return sqlt, nil
|
return sqlt, nil
|
||||||
|
@ -196,14 +188,19 @@ func (sqlt *sqlite) free(ptr uint32) {
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sqlt.call("free", uint64(ptr))
|
sqlt.call("sqlite3_free", uint64(ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sqlt *sqlite) new(size uint64) uint32 {
|
func (sqlt *sqlite) new(size uint64) uint32 {
|
||||||
if size > _MAX_ALLOCATION_SIZE {
|
ptr := uint32(sqlt.call("sqlite3_malloc64", size))
|
||||||
|
if ptr == 0 && size != 0 {
|
||||||
panic(util.OOMErr)
|
panic(util.OOMErr)
|
||||||
}
|
}
|
||||||
ptr := uint32(sqlt.call("malloc", size))
|
return ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sqlt *sqlite) realloc(ptr uint32, size uint64) uint32 {
|
||||||
|
ptr = uint32(sqlt.call("sqlite3_realloc64", uint64(ptr), size))
|
||||||
if ptr == 0 && size != 0 {
|
if ptr == 0 && size != 0 {
|
||||||
panic(util.OOMErr)
|
panic(util.OOMErr)
|
||||||
}
|
}
|
||||||
|
@ -214,7 +211,11 @@ func (sqlt *sqlite) newBytes(b []byte) uint32 {
|
||||||
if (*[0]byte)(b) == nil {
|
if (*[0]byte)(b) == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
ptr := sqlt.new(uint64(len(b)))
|
size := len(b)
|
||||||
|
if size == 0 {
|
||||||
|
size = 1
|
||||||
|
}
|
||||||
|
ptr := sqlt.new(uint64(size))
|
||||||
util.WriteBytes(sqlt.mod, ptr, b)
|
util.WriteBytes(sqlt.mod, ptr, b)
|
||||||
return ptr
|
return ptr
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,10 +246,9 @@ func (s *Stmt) BindText(param int, value string) error {
|
||||||
return TOOBIG
|
return TOOBIG
|
||||||
}
|
}
|
||||||
ptr := s.c.newString(value)
|
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(s.handle), uint64(param),
|
||||||
uint64(ptr), uint64(len(value)),
|
uint64(ptr), uint64(len(value)))
|
||||||
uint64(s.c.freer), _UTF8)
|
|
||||||
return s.c.error(r)
|
return s.c.error(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,10 +261,9 @@ func (s *Stmt) BindRawText(param int, value []byte) error {
|
||||||
return TOOBIG
|
return TOOBIG
|
||||||
}
|
}
|
||||||
ptr := s.c.newBytes(value)
|
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(s.handle), uint64(param),
|
||||||
uint64(ptr), uint64(len(value)),
|
uint64(ptr), uint64(len(value)))
|
||||||
uint64(s.c.freer), _UTF8)
|
|
||||||
return s.c.error(r)
|
return s.c.error(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,10 +277,9 @@ func (s *Stmt) BindBlob(param int, value []byte) error {
|
||||||
return TOOBIG
|
return TOOBIG
|
||||||
}
|
}
|
||||||
ptr := s.c.newBytes(value)
|
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(s.handle), uint64(param),
|
||||||
uint64(ptr), uint64(len(value)),
|
uint64(ptr), uint64(len(value)))
|
||||||
uint64(s.c.freer))
|
|
||||||
return s.c.error(r)
|
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 := util.View(s.c.mod, ptr, maxlen)
|
||||||
buf = value.AppendFormat(buf[:0], time.RFC3339Nano)
|
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(s.handle), uint64(param),
|
||||||
uint64(ptr), uint64(len(buf)),
|
uint64(ptr), uint64(len(buf)))
|
||||||
uint64(s.c.freer), _UTF8)
|
|
||||||
return s.c.error(r)
|
return s.c.error(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,16 +79,15 @@ func (f *vfsFile) Lock(lock LockLevel) error {
|
||||||
// A PENDING lock is needed before acquiring an EXCLUSIVE lock.
|
// A PENDING lock is needed before acquiring an EXCLUSIVE lock.
|
||||||
if f.lock < LOCK_PENDING {
|
if f.lock < LOCK_PENDING {
|
||||||
// If we're already RESERVED, we can block indefinitely,
|
// If we're already RESERVED, we can block indefinitely,
|
||||||
// since only new readers may briefly hold the PENDING lock.
|
// since only incoming readers may briefly hold the PENDING lock.
|
||||||
if rc := osGetPendingLock(f.File, reserved /* block */); rc != _OK {
|
if rc := osGetPendingLock(f.File, reserved /* block */); rc != _OK {
|
||||||
return rc
|
return rc
|
||||||
}
|
}
|
||||||
f.lock = LOCK_PENDING
|
f.lock = LOCK_PENDING
|
||||||
}
|
}
|
||||||
// We already have PENDING, so we're just waiting for readers to leave.
|
// We are now PENDING, so we're just waiting for readers to leave.
|
||||||
// If we were RESERVED, we can wait for a little while, before invoking
|
// If we were RESERVED, we can block for a bit before invoking the busy handler.
|
||||||
// the busy handler; we will only do this once.
|
if rc := osGetExclusiveLock(f.File, reserved /* block */); rc != _OK {
|
||||||
if rc := osGetExclusiveLock(f.File, reserved /* wait */); rc != _OK {
|
|
||||||
return rc
|
return rc
|
||||||
}
|
}
|
||||||
f.lock = LOCK_EXCLUSIVE
|
f.lock = LOCK_EXCLUSIVE
|
||||||
|
|
|
@ -53,10 +53,11 @@ func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, d
|
||||||
if errno, _ := err.(unix.Errno); errno != unix.EAGAIN {
|
if errno, _ := err.(unix.Errno); errno != unix.EAGAIN {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if timeout < time.Since(before) {
|
if time.Since(before) > timeout {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(time.Duration(rand.Int63n(int64(time.Millisecond))))
|
const sleepIncrement = 1024*1024 - 1 // power of two, ~1ms
|
||||||
|
time.Sleep(time.Duration(rand.Int63() & sleepIncrement))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return osLockErrorCode(err, def)
|
return osLockErrorCode(err, def)
|
||||||
|
|
|
@ -32,9 +32,9 @@ func osGetPendingLock(file *os.File, block bool) _ErrorCode {
|
||||||
return osWriteLock(file, _PENDING_BYTE, 1, timeout)
|
return osWriteLock(file, _PENDING_BYTE, 1, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
func osGetExclusiveLock(file *os.File, wait bool) _ErrorCode {
|
func osGetExclusiveLock(file *os.File, block bool) _ErrorCode {
|
||||||
var timeout time.Duration
|
var timeout time.Duration
|
||||||
if wait {
|
if block {
|
||||||
timeout = time.Millisecond
|
timeout = time.Millisecond
|
||||||
}
|
}
|
||||||
// Acquire the EXCLUSIVE lock.
|
// Acquire the EXCLUSIVE lock.
|
||||||
|
|
|
@ -38,9 +38,9 @@ func osGetPendingLock(file *os.File, block bool) _ErrorCode {
|
||||||
return osWriteLock(file, _PENDING_BYTE, 1, timeout)
|
return osWriteLock(file, _PENDING_BYTE, 1, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
func osGetExclusiveLock(file *os.File, wait bool) _ErrorCode {
|
func osGetExclusiveLock(file *os.File, block bool) _ErrorCode {
|
||||||
var timeout time.Duration
|
var timeout time.Duration
|
||||||
if wait {
|
if block {
|
||||||
timeout = time.Millisecond
|
timeout = time.Millisecond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,10 +134,11 @@ func osLock(file *os.File, flags, start, len uint32, timeout time.Duration, def
|
||||||
if errno, _ := err.(windows.Errno); errno != windows.ERROR_LOCK_VIOLATION {
|
if errno, _ := err.(windows.Errno); errno != windows.ERROR_LOCK_VIOLATION {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if timeout < time.Since(before) {
|
if time.Since(before) > timeout {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(time.Duration(rand.Int63n(int64(time.Millisecond))))
|
const sleepIncrement = 1024*1024 - 1 // power of two, ~1ms
|
||||||
|
time.Sleep(time.Duration(rand.Int63() & sleepIncrement))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return osLockErrorCode(err, def)
|
return osLockErrorCode(err, def)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ncruces/go-sqlite3/internal/util"
|
"github.com/ncruces/go-sqlite3/internal/util"
|
||||||
"github.com/tetratelabs/wazero/api"
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
@ -49,6 +50,7 @@ type vfsShm struct {
|
||||||
path string
|
path string
|
||||||
regions []*util.MappedRegion
|
regions []*util.MappedRegion
|
||||||
readOnly bool
|
readOnly bool
|
||||||
|
blocking bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmOpen() _ErrorCode {
|
func (s *vfsShm) shmOpen() _ErrorCode {
|
||||||
|
@ -76,6 +78,13 @@ func (s *vfsShm) shmOpen() _ErrorCode {
|
||||||
if s.readOnly {
|
if s.readOnly {
|
||||||
return _READONLY_CANTINIT
|
return _READONLY_CANTINIT
|
||||||
}
|
}
|
||||||
|
// Do not use a blocking lock here.
|
||||||
|
// If the lock cannot be obtained immediately,
|
||||||
|
// it means some other connection is truncating the file.
|
||||||
|
// And after it has done so, it will not release its lock,
|
||||||
|
// but only downgrade it to a shared lock.
|
||||||
|
// So no point in blocking here.
|
||||||
|
// The call below to obtain the shared DMS lock may use a blocking lock.
|
||||||
if rc := osWriteLock(s.File, _SHM_DMS, 1, 0); rc != _OK {
|
if rc := osWriteLock(s.File, _SHM_DMS, 1, 0); rc != _OK {
|
||||||
return rc
|
return rc
|
||||||
}
|
}
|
||||||
|
@ -83,7 +92,7 @@ func (s *vfsShm) shmOpen() _ErrorCode {
|
||||||
return _IOERR_SHMOPEN
|
return _IOERR_SHMOPEN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if rc := osReadLock(s.File, _SHM_DMS, 1, 0); rc != _OK {
|
if rc := osReadLock(s.File, _SHM_DMS, 1, time.Millisecond); rc != _OK {
|
||||||
return rc
|
return rc
|
||||||
}
|
}
|
||||||
return _OK
|
return _OK
|
||||||
|
@ -150,13 +159,18 @@ func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
|
||||||
panic(util.AssertErr())
|
panic(util.AssertErr())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var timeout time.Duration
|
||||||
|
if s.blocking {
|
||||||
|
timeout = time.Millisecond
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case flags&_SHM_UNLOCK != 0:
|
case flags&_SHM_UNLOCK != 0:
|
||||||
return osUnlock(s.File, _SHM_BASE+int64(offset), int64(n))
|
return osUnlock(s.File, _SHM_BASE+int64(offset), int64(n))
|
||||||
case flags&_SHM_SHARED != 0:
|
case flags&_SHM_SHARED != 0:
|
||||||
return osReadLock(s.File, _SHM_BASE+int64(offset), int64(n), 0)
|
return osReadLock(s.File, _SHM_BASE+int64(offset), int64(n), timeout)
|
||||||
case flags&_SHM_EXCLUSIVE != 0:
|
case flags&_SHM_EXCLUSIVE != 0:
|
||||||
return osWriteLock(s.File, _SHM_BASE+int64(offset), int64(n), 0)
|
return osWriteLock(s.File, _SHM_BASE+int64(offset), int64(n), timeout)
|
||||||
default:
|
default:
|
||||||
panic(util.AssertErr())
|
panic(util.AssertErr())
|
||||||
}
|
}
|
||||||
|
@ -181,3 +195,7 @@ func (s *vfsShm) shmUnmap(delete bool) {
|
||||||
s.Close()
|
s.Close()
|
||||||
s.File = nil
|
s.File = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *vfsShm) shmEnableBlocking(block bool) {
|
||||||
|
s.blocking = block
|
||||||
|
}
|
||||||
|
|
|
@ -243,6 +243,15 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl
|
||||||
return _OK
|
return _OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case _FCNTL_LOCK_TIMEOUT:
|
||||||
|
if file, ok := file.(FileSharedMemory); ok {
|
||||||
|
if iface, ok := file.SharedMemory().(interface{ shmEnableBlocking(bool) }); ok {
|
||||||
|
if i := util.ReadUint32(mod, pArg); i == 0 || i == 1 {
|
||||||
|
iface.shmEnableBlocking(i != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case _FCNTL_PERSIST_WAL:
|
case _FCNTL_PERSIST_WAL:
|
||||||
if file, ok := file.(FilePersistentWAL); ok {
|
if file, ok := file.(FilePersistentWAL); ok {
|
||||||
if i := util.ReadUint32(mod, pArg); int32(i) >= 0 {
|
if i := util.ReadUint32(mod, pArg); int32(i) >= 0 {
|
||||||
|
@ -347,7 +356,7 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl
|
||||||
out = err.Error()
|
out = err.Error()
|
||||||
}
|
}
|
||||||
if out != "" {
|
if out != "" {
|
||||||
fn := mod.ExportedFunction("malloc")
|
fn := mod.ExportedFunction("sqlite3_malloc64")
|
||||||
stack := [...]uint64{uint64(len(out) + 1)}
|
stack := [...]uint64{uint64(len(out) + 1)}
|
||||||
if err := fn.CallWithStack(ctx, stack[:]); err != nil {
|
if err := fn.CallWithStack(ctx, stack[:]); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -523,7 +523,7 @@ github.com/modern-go/reflect2
|
||||||
# github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
|
# github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
|
||||||
## explicit
|
## explicit
|
||||||
github.com/munnerz/goautoneg
|
github.com/munnerz/goautoneg
|
||||||
# github.com/ncruces/go-sqlite3 v0.18.1
|
# github.com/ncruces/go-sqlite3 v0.18.3
|
||||||
## explicit; go 1.21
|
## explicit; go 1.21
|
||||||
github.com/ncruces/go-sqlite3
|
github.com/ncruces/go-sqlite3
|
||||||
github.com/ncruces/go-sqlite3/driver
|
github.com/ncruces/go-sqlite3/driver
|
||||||
|
|
Loading…
Reference in New Issue