bump ncruces/go-sqlite3 to v0.21.0 (#3621)
This commit is contained in:
parent
60acdb21a9
commit
fb12bbb10b
4
go.mod
4
go.mod
|
@ -62,7 +62,7 @@ require (
|
||||||
github.com/miekg/dns v1.1.62
|
github.com/miekg/dns v1.1.62
|
||||||
github.com/minio/minio-go/v7 v7.0.81
|
github.com/minio/minio-go/v7 v7.0.81
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/ncruces/go-sqlite3 v0.20.3
|
github.com/ncruces/go-sqlite3 v0.21.0
|
||||||
github.com/oklog/ulid v1.3.1
|
github.com/oklog/ulid v1.3.1
|
||||||
github.com/prometheus/client_golang v1.20.5
|
github.com/prometheus/client_golang v1.20.5
|
||||||
github.com/spf13/cobra v1.8.1
|
github.com/spf13/cobra v1.8.1
|
||||||
|
@ -91,7 +91,7 @@ require (
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.32.0
|
go.opentelemetry.io/otel/sdk/metric v1.32.0
|
||||||
go.opentelemetry.io/otel/trace v1.32.0
|
go.opentelemetry.io/otel/trace v1.32.0
|
||||||
go.uber.org/automaxprocs v1.6.0
|
go.uber.org/automaxprocs v1.6.0
|
||||||
golang.org/x/crypto v0.30.0
|
golang.org/x/crypto v0.31.0
|
||||||
golang.org/x/image v0.23.0
|
golang.org/x/image v0.23.0
|
||||||
golang.org/x/net v0.32.0
|
golang.org/x/net v0.32.0
|
||||||
golang.org/x/oauth2 v0.24.0
|
golang.org/x/oauth2 v0.24.0
|
||||||
|
|
|
@ -434,8 +434,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.20.3 h1:+4G4uEqOeusF0yRuQVUl9fuoEebUolwQSnBUjYBLYIw=
|
github.com/ncruces/go-sqlite3 v0.21.0 h1:EwKFoy1hHEopN4sFZarmi+McXdbCcbTuLixhEayXVbQ=
|
||||||
github.com/ncruces/go-sqlite3 v0.20.3/go.mod h1:ojLIAB243gtz68Eo283Ps+k9PyR3dvzS+9/RgId4+AA=
|
github.com/ncruces/go-sqlite3 v0.21.0/go.mod h1:zxMOaSG5kFYVFK4xQa0pdwIszqxqJ0W0BxBgwdrNjuA=
|
||||||
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=
|
||||||
|
@ -675,8 +675,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||||
golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
|
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||||
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
|
|
@ -10,7 +10,7 @@ as well as direct access to most of the [C SQLite API](https://sqlite.org/cintro
|
||||||
|
|
||||||
It wraps a [Wasm](https://webassembly.org/) [build](embed/) of SQLite,
|
It wraps a [Wasm](https://webassembly.org/) [build](embed/) of SQLite,
|
||||||
and uses [wazero](https://wazero.io/) as the runtime.\
|
and uses [wazero](https://wazero.io/) as the runtime.\
|
||||||
Go, wazero and [`x/sys`](https://pkg.go.dev/golang.org/x/sys) are the _only_ runtime dependencies.
|
Go, wazero and [`x/sys`](https://pkg.go.dev/golang.org/x/sys) are the _only_ direct dependencies.
|
||||||
|
|
||||||
### Getting started
|
### Getting started
|
||||||
|
|
||||||
|
|
|
@ -501,8 +501,12 @@ func (c *Conn) TableColumnMetadata(schema, table, column string) (declType, coll
|
||||||
uint64(declTypePtr), uint64(collSeqPtr),
|
uint64(declTypePtr), uint64(collSeqPtr),
|
||||||
uint64(notNullPtr), uint64(primaryKeyPtr), uint64(autoIncPtr))
|
uint64(notNullPtr), uint64(primaryKeyPtr), uint64(autoIncPtr))
|
||||||
if err = c.error(r); err == nil && column != "" {
|
if err = c.error(r); err == nil && column != "" {
|
||||||
declType = util.ReadString(c.mod, util.ReadUint32(c.mod, declTypePtr), _MAX_NAME)
|
if ptr := util.ReadUint32(c.mod, declTypePtr); ptr != 0 {
|
||||||
collSeq = util.ReadString(c.mod, util.ReadUint32(c.mod, collSeqPtr), _MAX_NAME)
|
declType = util.ReadString(c.mod, ptr, _MAX_NAME)
|
||||||
|
}
|
||||||
|
if ptr := util.ReadUint32(c.mod, collSeqPtr); ptr != 0 {
|
||||||
|
collSeq = util.ReadString(c.mod, ptr, _MAX_NAME)
|
||||||
|
}
|
||||||
notNull = util.ReadUint32(c.mod, notNullPtr) != 0
|
notNull = util.ReadUint32(c.mod, notNullPtr) != 0
|
||||||
autoInc = util.ReadUint32(c.mod, autoIncPtr) != 0
|
autoInc = util.ReadUint32(c.mod, autoIncPtr) != 0
|
||||||
primaryKey = util.ReadUint32(c.mod, primaryKeyPtr) != 0
|
primaryKey = util.ReadUint32(c.mod, primaryKeyPtr) != 0
|
||||||
|
|
|
@ -81,6 +81,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
@ -107,17 +108,17 @@ func init() {
|
||||||
// The second callback is called before the driver closes a connection.
|
// The second callback is called before the driver closes a connection.
|
||||||
// The [sqlite3.Conn] can be used to execute queries, register functions, etc.
|
// The [sqlite3.Conn] can be used to execute queries, register functions, etc.
|
||||||
func Open(dataSourceName string, fn ...func(*sqlite3.Conn) error) (*sql.DB, error) {
|
func Open(dataSourceName string, fn ...func(*sqlite3.Conn) error) (*sql.DB, error) {
|
||||||
var drv SQLite
|
|
||||||
if len(fn) > 2 {
|
if len(fn) > 2 {
|
||||||
return nil, sqlite3.MISUSE
|
return nil, sqlite3.MISUSE
|
||||||
}
|
}
|
||||||
|
var init, term func(*sqlite3.Conn) error
|
||||||
if len(fn) > 1 {
|
if len(fn) > 1 {
|
||||||
drv.term = fn[1]
|
term = fn[1]
|
||||||
}
|
}
|
||||||
if len(fn) > 0 {
|
if len(fn) > 0 {
|
||||||
drv.init = fn[0]
|
init = fn[0]
|
||||||
}
|
}
|
||||||
c, err := drv.OpenConnector(dataSourceName)
|
c, err := newConnector(dataSourceName, init, term)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -125,10 +126,7 @@ func Open(dataSourceName string, fn ...func(*sqlite3.Conn) error) (*sql.DB, erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// SQLite implements [database/sql/driver.Driver].
|
// SQLite implements [database/sql/driver.Driver].
|
||||||
type SQLite struct {
|
type SQLite struct{}
|
||||||
init func(*sqlite3.Conn) error
|
|
||||||
term func(*sqlite3.Conn) error
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Ensure these interfaces are implemented:
|
// Ensure these interfaces are implemented:
|
||||||
|
@ -137,7 +135,7 @@ var (
|
||||||
|
|
||||||
// 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 := newConnector(name, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -146,11 +144,11 @@ func (d *SQLite) Open(name string) (driver.Conn, error) {
|
||||||
|
|
||||||
// OpenConnector implements [database/sql/driver.DriverContext].
|
// OpenConnector implements [database/sql/driver.DriverContext].
|
||||||
func (d *SQLite) OpenConnector(name string) (driver.Connector, error) {
|
func (d *SQLite) OpenConnector(name string) (driver.Connector, error) {
|
||||||
return d.newConnector(name)
|
return newConnector(name, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *SQLite) newConnector(name string) (*connector, error) {
|
func newConnector(name string, init, term func(*sqlite3.Conn) error) (*connector, error) {
|
||||||
c := connector{driver: d, name: name}
|
c := connector{name: name, init: init, term: term}
|
||||||
|
|
||||||
var txlock, timefmt string
|
var txlock, timefmt string
|
||||||
if strings.HasPrefix(name, "file:") {
|
if strings.HasPrefix(name, "file:") {
|
||||||
|
@ -190,7 +188,8 @@ func (d *SQLite) newConnector(name string) (*connector, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type connector struct {
|
type connector struct {
|
||||||
driver *SQLite
|
init func(*sqlite3.Conn) error
|
||||||
|
term func(*sqlite3.Conn) error
|
||||||
name string
|
name string
|
||||||
txLock string
|
txLock string
|
||||||
tmRead sqlite3.TimeFormat
|
tmRead sqlite3.TimeFormat
|
||||||
|
@ -199,7 +198,7 @@ type connector struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *connector) Driver() driver.Driver {
|
func (n *connector) Driver() driver.Driver {
|
||||||
return n.driver
|
return &SQLite{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *connector) Connect(ctx context.Context) (res driver.Conn, err error) {
|
func (n *connector) Connect(ctx context.Context) (res driver.Conn, err error) {
|
||||||
|
@ -228,13 +227,13 @@ func (n *connector) Connect(ctx context.Context) (res driver.Conn, err error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if n.driver.init != nil {
|
if n.init != nil {
|
||||||
err = n.driver.init(c.Conn)
|
err = n.init(c.Conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if n.pragmas || n.driver.init != nil {
|
if n.pragmas || n.init != nil {
|
||||||
s, _, err := c.Conn.Prepare(`PRAGMA query_only`)
|
s, _, err := c.Conn.Prepare(`PRAGMA query_only`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -250,9 +249,9 @@ func (n *connector) Connect(ctx context.Context) (res driver.Conn, err error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if n.driver.term != nil {
|
if n.term != nil {
|
||||||
err = c.Conn.Trace(sqlite3.TRACE_CLOSE, func(sqlite3.TraceEvent, any, any) error {
|
err = c.Conn.Trace(sqlite3.TRACE_CLOSE, func(sqlite3.TraceEvent, any, any) error {
|
||||||
return n.driver.term(c.Conn)
|
return n.term(c.Conn)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -288,6 +287,8 @@ func (n *connector) Connect(ctx context.Context) (res driver.Conn, err error) {
|
||||||
type Conn interface {
|
type Conn interface {
|
||||||
Raw() *sqlite3.Conn
|
Raw() *sqlite3.Conn
|
||||||
driver.Conn
|
driver.Conn
|
||||||
|
driver.ConnBeginTx
|
||||||
|
driver.ConnPrepareContext
|
||||||
}
|
}
|
||||||
|
|
||||||
type conn struct {
|
type conn struct {
|
||||||
|
@ -301,10 +302,8 @@ type conn struct {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Ensure these interfaces are implemented:
|
// Ensure these interfaces are implemented:
|
||||||
_ Conn = &conn{}
|
_ Conn = &conn{}
|
||||||
_ driver.ConnBeginTx = &conn{}
|
_ driver.ExecerContext = &conn{}
|
||||||
_ driver.ConnPrepareContext = &conn{}
|
|
||||||
_ driver.ExecerContext = &conn{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *conn) Raw() *sqlite3.Conn {
|
func (c *conn) Raw() *sqlite3.Conn {
|
||||||
|
@ -581,8 +580,22 @@ type rows struct {
|
||||||
names []string
|
names []string
|
||||||
types []string
|
types []string
|
||||||
nulls []bool
|
nulls []bool
|
||||||
|
scans []scantype
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type scantype byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ANY scantype = iota
|
||||||
|
_INT scantype = scantype(sqlite3.INTEGER)
|
||||||
|
_REAL scantype = scantype(sqlite3.FLOAT)
|
||||||
|
_TEXT scantype = scantype(sqlite3.TEXT)
|
||||||
|
_BLOB scantype = scantype(sqlite3.BLOB)
|
||||||
|
_NULL scantype = scantype(sqlite3.NULL)
|
||||||
|
_BOOL scantype = iota
|
||||||
|
_TIME
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Ensure these interfaces are implemented:
|
// Ensure these interfaces are implemented:
|
||||||
_ driver.RowsColumnTypeDatabaseTypeName = &rows{}
|
_ driver.RowsColumnTypeDatabaseTypeName = &rows{}
|
||||||
|
@ -606,21 +619,42 @@ func (r *rows) Columns() []string {
|
||||||
return r.names
|
return r.names
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *rows) loadTypes() {
|
func (r *rows) loadColumnMetadata() {
|
||||||
if r.nulls == nil {
|
if r.nulls == nil {
|
||||||
count := r.Stmt.ColumnCount()
|
count := r.Stmt.ColumnCount()
|
||||||
nulls := make([]bool, count)
|
nulls := make([]bool, count)
|
||||||
types := make([]string, count)
|
types := make([]string, count)
|
||||||
|
scans := make([]scantype, count)
|
||||||
for i := range nulls {
|
for i := range nulls {
|
||||||
if col := r.Stmt.ColumnOriginName(i); col != "" {
|
if col := r.Stmt.ColumnOriginName(i); col != "" {
|
||||||
types[i], _, nulls[i], _, _, _ = r.Stmt.Conn().TableColumnMetadata(
|
types[i], _, nulls[i], _, _, _ = r.Stmt.Conn().TableColumnMetadata(
|
||||||
r.Stmt.ColumnDatabaseName(i),
|
r.Stmt.ColumnDatabaseName(i),
|
||||||
r.Stmt.ColumnTableName(i),
|
r.Stmt.ColumnTableName(i),
|
||||||
col)
|
col)
|
||||||
|
types[i] = strings.ToUpper(types[i])
|
||||||
|
// These types are only used before we have rows,
|
||||||
|
// and otherwise as type hints.
|
||||||
|
// The first few ensure STRICT tables are strictly typed.
|
||||||
|
// The other two are type hints for booleans and time.
|
||||||
|
switch types[i] {
|
||||||
|
case "INT", "INTEGER":
|
||||||
|
scans[i] = _INT
|
||||||
|
case "REAL":
|
||||||
|
scans[i] = _REAL
|
||||||
|
case "TEXT":
|
||||||
|
scans[i] = _TEXT
|
||||||
|
case "BLOB":
|
||||||
|
scans[i] = _BLOB
|
||||||
|
case "BOOLEAN":
|
||||||
|
scans[i] = _BOOL
|
||||||
|
case "DATE", "TIME", "DATETIME", "TIMESTAMP":
|
||||||
|
scans[i] = _TIME
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.nulls = nulls
|
r.nulls = nulls
|
||||||
r.types = types
|
r.types = types
|
||||||
|
r.scans = scans
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,7 +671,7 @@ func (r *rows) declType(index int) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *rows) ColumnTypeDatabaseTypeName(index int) string {
|
func (r *rows) ColumnTypeDatabaseTypeName(index int) string {
|
||||||
r.loadTypes()
|
r.loadColumnMetadata()
|
||||||
decltype := r.types[index]
|
decltype := r.types[index]
|
||||||
if len := len(decltype); len > 0 && decltype[len-1] == ')' {
|
if len := len(decltype); len > 0 && decltype[len-1] == ')' {
|
||||||
if i := strings.LastIndexByte(decltype, '('); i >= 0 {
|
if i := strings.LastIndexByte(decltype, '('); i >= 0 {
|
||||||
|
@ -648,13 +682,57 @@ func (r *rows) ColumnTypeDatabaseTypeName(index int) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *rows) ColumnTypeNullable(index int) (nullable, ok bool) {
|
func (r *rows) ColumnTypeNullable(index int) (nullable, ok bool) {
|
||||||
r.loadTypes()
|
r.loadColumnMetadata()
|
||||||
if r.nulls[index] {
|
if r.nulls[index] {
|
||||||
return false, true
|
return false, true
|
||||||
}
|
}
|
||||||
return true, false
|
return true, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *rows) ColumnTypeScanType(index int) (typ reflect.Type) {
|
||||||
|
r.loadColumnMetadata()
|
||||||
|
scan := r.scans[index]
|
||||||
|
|
||||||
|
if r.Stmt.Busy() {
|
||||||
|
// SQLite is dynamically typed and we now have a row.
|
||||||
|
// Always use the type of the value itself,
|
||||||
|
// unless the scan type is more specific
|
||||||
|
// and can scan the actual value.
|
||||||
|
val := scantype(r.Stmt.ColumnType(index))
|
||||||
|
useValType := true
|
||||||
|
switch {
|
||||||
|
case scan == _TIME && val != _BLOB && val != _NULL:
|
||||||
|
t := r.Stmt.ColumnTime(index, r.tmRead)
|
||||||
|
useValType = t == time.Time{}
|
||||||
|
case scan == _BOOL && val == _INT:
|
||||||
|
i := r.Stmt.ColumnInt64(index)
|
||||||
|
useValType = i != 0 && i != 1
|
||||||
|
case scan == _BLOB && val == _NULL:
|
||||||
|
useValType = false
|
||||||
|
}
|
||||||
|
if useValType {
|
||||||
|
scan = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch scan {
|
||||||
|
case _INT:
|
||||||
|
return reflect.TypeOf(int64(0))
|
||||||
|
case _REAL:
|
||||||
|
return reflect.TypeOf(float64(0))
|
||||||
|
case _TEXT:
|
||||||
|
return reflect.TypeOf("")
|
||||||
|
case _BLOB:
|
||||||
|
return reflect.TypeOf([]byte{})
|
||||||
|
case _BOOL:
|
||||||
|
return reflect.TypeOf(false)
|
||||||
|
case _TIME:
|
||||||
|
return reflect.TypeOf(time.Time{})
|
||||||
|
default:
|
||||||
|
return reflect.TypeOf((*any)(nil)).Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (r *rows) Next(dest []driver.Value) error {
|
func (r *rows) Next(dest []driver.Value) error {
|
||||||
old := r.Stmt.Conn().SetInterrupt(r.ctx)
|
old := r.Stmt.Conn().SetInterrupt(r.ctx)
|
||||||
defer r.Stmt.Conn().SetInterrupt(old)
|
defer r.Stmt.Conn().SetInterrupt(old)
|
||||||
|
@ -667,7 +745,7 @@ func (r *rows) Next(dest []driver.Value) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
data := unsafe.Slice((*any)(unsafe.SliceData(dest)), len(dest))
|
data := unsafe.Slice((*any)(unsafe.SliceData(dest)), len(dest))
|
||||||
err := r.Stmt.Columns(data)
|
err := r.Stmt.Columns(data...)
|
||||||
for i := range dest {
|
for i := range dest {
|
||||||
if t, ok := r.decodeTime(i, dest[i]); ok {
|
if t, ok := r.decodeTime(i, dest[i]); ok {
|
||||||
dest[i] = t
|
dest[i] = t
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package driver
|
package driver
|
||||||
|
|
||||||
import (
|
import "time"
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Convert a string in [time.RFC3339Nano] format into a [time.Time]
|
// Convert a string in [time.RFC3339Nano] format into a [time.Time]
|
||||||
// if it roundtrips back to the same string.
|
// if it roundtrips back to the same string.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Embeddable Wasm build of SQLite
|
# Embeddable Wasm build of SQLite
|
||||||
|
|
||||||
This folder includes an embeddable Wasm build of SQLite 3.47.1 for use with
|
This folder includes an embeddable Wasm build of SQLite 3.47.2 for use with
|
||||||
[`github.com/ncruces/go-sqlite3`](https://pkg.go.dev/github.com/ncruces/go-sqlite3).
|
[`github.com/ncruces/go-sqlite3`](https://pkg.go.dev/github.com/ncruces/go-sqlite3).
|
||||||
|
|
||||||
The following optional features are compiled in:
|
The following optional features are compiled in:
|
||||||
|
|
Binary file not shown.
|
@ -3,4 +3,5 @@ go 1.21
|
||||||
use (
|
use (
|
||||||
.
|
.
|
||||||
./gormlite
|
./gormlite
|
||||||
|
./embed/bcw2
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,5 +10,6 @@ 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/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
|
||||||
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
||||||
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
|
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
|
||||||
|
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||||
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=
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build !(unix || windows) || sqlite3_nosys
|
//go:build !unix && !windows
|
||||||
|
|
||||||
package alloc
|
package alloc
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build unix && !sqlite3_nosys
|
//go:build unix
|
||||||
|
|
||||||
package alloc
|
package alloc
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
//go:build !sqlite3_nosys
|
|
||||||
|
|
||||||
package alloc
|
package alloc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build !unix || sqlite3_nosys
|
//go:build !unix
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build unix && !sqlite3_nosys
|
//go:build unix
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
//go:build !sqlite3_nosys
|
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -582,7 +582,9 @@ func (s *Stmt) ColumnRawBlob(col int) []byte {
|
||||||
func (s *Stmt) columnRawBytes(col int, ptr uint32) []byte {
|
func (s *Stmt) columnRawBytes(col int, ptr uint32) []byte {
|
||||||
if ptr == 0 {
|
if ptr == 0 {
|
||||||
r := s.c.call("sqlite3_errcode", uint64(s.c.handle))
|
r := s.c.call("sqlite3_errcode", uint64(s.c.handle))
|
||||||
s.err = s.c.error(r)
|
if r != _ROW && r != _DONE {
|
||||||
|
s.err = s.c.error(r)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,7 +639,7 @@ func (s *Stmt) ColumnValue(col int) Value {
|
||||||
// [TEXT] as string, and [BLOB] as []byte.
|
// [TEXT] as string, and [BLOB] as []byte.
|
||||||
// Any []byte are owned by SQLite and may be invalidated by
|
// Any []byte are owned by SQLite and may be invalidated by
|
||||||
// subsequent calls to [Stmt] methods.
|
// subsequent calls to [Stmt] methods.
|
||||||
func (s *Stmt) Columns(dest []any) error {
|
func (s *Stmt) Columns(dest ...any) error {
|
||||||
defer s.c.arena.mark()()
|
defer s.c.arena.mark()()
|
||||||
count := uint64(len(dest))
|
count := uint64(len(dest))
|
||||||
typePtr := s.c.arena.new(count)
|
typePtr := s.c.arena.new(count)
|
||||||
|
@ -666,6 +668,10 @@ func (s *Stmt) Columns(dest []any) error {
|
||||||
dest[i] = nil
|
dest[i] = nil
|
||||||
default:
|
default:
|
||||||
ptr := util.ReadUint32(s.c.mod, dataPtr+0)
|
ptr := util.ReadUint32(s.c.mod, dataPtr+0)
|
||||||
|
if ptr == 0 {
|
||||||
|
dest[i] = []byte{}
|
||||||
|
continue
|
||||||
|
}
|
||||||
len := util.ReadUint32(s.c.mod, dataPtr+4)
|
len := util.ReadUint32(s.c.mod, dataPtr+4)
|
||||||
buf := util.View(s.c.mod, ptr, uint64(len))
|
buf := util.View(s.c.mod, ptr, uint64(len))
|
||||||
if types[i] == byte(TEXT) {
|
if types[i] == byte(TEXT) {
|
||||||
|
|
|
@ -101,6 +101,9 @@ func syscallOpen(path string, mode int, perm uint32) (fd Handle, err error) {
|
||||||
const _FILE_FLAG_WRITE_THROUGH = 0x80000000
|
const _FILE_FLAG_WRITE_THROUGH = 0x80000000
|
||||||
attrs |= _FILE_FLAG_WRITE_THROUGH
|
attrs |= _FILE_FLAG_WRITE_THROUGH
|
||||||
}
|
}
|
||||||
|
if mode&O_NONBLOCK != 0 {
|
||||||
|
attrs |= FILE_FLAG_OVERLAPPED
|
||||||
|
}
|
||||||
return CreateFile(pathp, access, sharemode, sa, createmode, attrs, 0)
|
return CreateFile(pathp, access, sharemode, sa, createmode, attrs, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,6 @@ The implementation is compatible with SQLite's
|
||||||
The VFS can be customized with a few build tags:
|
The VFS can be customized with a few build tags:
|
||||||
- `sqlite3_flock` forces the use of BSD locks.
|
- `sqlite3_flock` forces the use of BSD locks.
|
||||||
- `sqlite3_dotlk` forces the use of dot-file locks.
|
- `sqlite3_dotlk` forces the use of dot-file locks.
|
||||||
- `sqlite3_nosys` prevents importing [`x/sys`](https://pkg.go.dev/golang.org/x/sys).
|
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> The default configuration of this package is compatible with the standard
|
> The default configuration of this package is compatible with the standard
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build ((linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos) && !sqlite3_nosys) || sqlite3_flock || sqlite3_dotlk
|
//go:build linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock || sqlite3_dotlk
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build !(((linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos) && !sqlite3_nosys) || sqlite3_flock || sqlite3_dotlk)
|
//go:build !(linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock || sqlite3_dotlk)
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build ((freebsd || openbsd || netbsd || dragonfly || illumos) && !(sqlite3_dotlk || sqlite3_nosys)) || sqlite3_flock
|
//go:build ((freebsd || openbsd || netbsd || dragonfly || illumos) && !sqlite3_dotlk) || sqlite3_flock
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build !(sqlite3_flock || sqlite3_nosys)
|
//go:build !sqlite3_flock
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build (amd64 || arm64 || riscv64) && !sqlite3_nosys
|
//go:build amd64 || arm64 || riscv64
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build !(sqlite3_flock || sqlite3_nosys)
|
//go:build !sqlite3_flock
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build (linux || darwin) && !(sqlite3_flock || sqlite3_dotlk || sqlite3_nosys)
|
//go:build (linux || darwin) && !(sqlite3_flock || sqlite3_dotlk)
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build !unix || sqlite3_nosys
|
//go:build !unix
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build !(linux || darwin) || sqlite3_flock || sqlite3_nosys
|
//go:build !(linux || darwin) || sqlite3_flock
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build !linux || !(amd64 || arm64 || riscv64) || sqlite3_nosys
|
//go:build !linux || !(amd64 || arm64 || riscv64)
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build !(linux || darwin) || sqlite3_flock || sqlite3_nosys
|
//go:build !(linux || darwin) || sqlite3_flock
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build unix && !sqlite3_nosys
|
//go:build unix
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
//go:build !(sqlite3_dotlk || sqlite3_nosys)
|
//go:build !sqlite3_dotlk
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -46,7 +45,7 @@ func osGetExclusiveLock(file *os.File, state *LockLevel) _ErrorCode {
|
||||||
osUnlock(file, _SHARED_FIRST, _SHARED_SIZE)
|
osUnlock(file, _SHARED_FIRST, _SHARED_SIZE)
|
||||||
|
|
||||||
// Acquire the EXCLUSIVE lock.
|
// Acquire the EXCLUSIVE lock.
|
||||||
rc := osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, time.Millisecond)
|
rc := osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, 0)
|
||||||
|
|
||||||
if rc != _OK {
|
if rc != _OK {
|
||||||
// Reacquire the SHARED lock.
|
// Reacquire the SHARED lock.
|
||||||
|
@ -123,29 +122,40 @@ func osLock(file *os.File, flags, start, len uint32, timeout time.Duration, def
|
||||||
var err error
|
var err error
|
||||||
switch {
|
switch {
|
||||||
case timeout == 0:
|
case timeout == 0:
|
||||||
err = osLockEx(file, flags|windows.LOCKFILE_FAIL_IMMEDIATELY, start, len)
|
err = osLockEx(file, flags|windows.LOCKFILE_FAIL_IMMEDIATELY, start, len, 0)
|
||||||
case timeout < 0:
|
case timeout < 0:
|
||||||
err = osLockEx(file, flags, start, len)
|
err = osLockEx(file, flags, start, len, 0)
|
||||||
default:
|
default:
|
||||||
before := time.Now()
|
var event windows.Handle
|
||||||
for {
|
event, err = windows.CreateEvent(nil, 1, 0, nil)
|
||||||
err = osLockEx(file, flags|windows.LOCKFILE_FAIL_IMMEDIATELY, start, len)
|
if err != nil {
|
||||||
if errno, _ := err.(windows.Errno); errno != windows.ERROR_LOCK_VIOLATION {
|
break
|
||||||
break
|
}
|
||||||
|
defer windows.CloseHandle(event)
|
||||||
|
|
||||||
|
err = osLockEx(file, flags, start, len, event)
|
||||||
|
if err == windows.ERROR_IO_PENDING {
|
||||||
|
rc, serr := windows.WaitForSingleObject(event, uint32(timeout/time.Millisecond))
|
||||||
|
if rc == windows.WAIT_OBJECT_0 {
|
||||||
|
return _OK
|
||||||
}
|
}
|
||||||
if time.Since(before) > timeout {
|
if serr != nil {
|
||||||
break
|
err = serr
|
||||||
|
} else {
|
||||||
|
err = windows.Errno(rc)
|
||||||
}
|
}
|
||||||
const sleepIncrement = 1024*1024 - 1 // power of two, ~1ms
|
windows.CancelIo(windows.Handle(file.Fd()))
|
||||||
time.Sleep(time.Duration(rand.Int63() & sleepIncrement))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return osLockErrorCode(err, def)
|
return osLockErrorCode(err, def)
|
||||||
}
|
}
|
||||||
|
|
||||||
func osLockEx(file *os.File, flags, start, len uint32) error {
|
func osLockEx(file *os.File, flags, start, len uint32, event windows.Handle) error {
|
||||||
return windows.LockFileEx(windows.Handle(file.Fd()), flags,
|
return windows.LockFileEx(windows.Handle(file.Fd()), flags,
|
||||||
0, len, 0, &windows.Overlapped{Offset: start})
|
0, len, 0, &windows.Overlapped{
|
||||||
|
Offset: start,
|
||||||
|
HEvent: event,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func osReadLock(file *os.File, start, len uint32, timeout time.Duration) _ErrorCode {
|
func osReadLock(file *os.File, start, len uint32, timeout time.Duration) _ErrorCode {
|
||||||
|
@ -166,7 +176,8 @@ func osLockErrorCode(err error, def _ErrorCode) _ErrorCode {
|
||||||
case
|
case
|
||||||
windows.ERROR_LOCK_VIOLATION,
|
windows.ERROR_LOCK_VIOLATION,
|
||||||
windows.ERROR_IO_PENDING,
|
windows.ERROR_IO_PENDING,
|
||||||
windows.ERROR_OPERATION_ABORTED:
|
windows.ERROR_OPERATION_ABORTED,
|
||||||
|
windows.WAIT_TIMEOUT:
|
||||||
return _BUSY
|
return _BUSY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build ((linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !sqlite3_nosys) || sqlite3_flock || sqlite3_dotlk
|
//go:build ((linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le)) || sqlite3_flock || sqlite3_dotlk
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build ((freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_dotlk || sqlite3_nosys)) || sqlite3_flock
|
//go:build ((freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !sqlite3_dotlk) || sqlite3_flock
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ func (s *vfsShm) shmOpen() _ErrorCode {
|
||||||
|
|
||||||
// Always open file read-write, as it will be shared.
|
// Always open file read-write, as it will be shared.
|
||||||
f, err := os.OpenFile(s.path,
|
f, err := os.OpenFile(s.path,
|
||||||
unix.O_RDWR|unix.O_CREAT|unix.O_NOFOLLOW, 0666)
|
os.O_RDWR|os.O_CREATE|_O_NOFOLLOW, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return _CANTOPEN
|
return _CANTOPEN
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build (windows && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !sqlite3_nosys) || sqlite3_dotlk
|
//go:build (windows && (386 || arm || amd64 || arm64 || riscv64 || ppc64le)) || sqlite3_dotlk
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ const (
|
||||||
_WALINDEX_PGSZ = 32768
|
_WALINDEX_PGSZ = 32768
|
||||||
)
|
)
|
||||||
|
|
||||||
// This looks like a safe way of keeping the WAL-index in sync.
|
// This seems a safe way of keeping the WAL-index in sync.
|
||||||
//
|
//
|
||||||
// The WAL-index file starts with a header,
|
// The WAL-index file starts with a header,
|
||||||
// and the index doesn't meaningfully change if the header doesn't change.
|
// and the index doesn't meaningfully change if the header doesn't change.
|
||||||
|
@ -27,7 +27,7 @@ const (
|
||||||
//
|
//
|
||||||
// Since all the data is either redundant+checksummed,
|
// Since all the data is either redundant+checksummed,
|
||||||
// 4 byte aligned, or modified under an exclusive lock,
|
// 4 byte aligned, or modified under an exclusive lock,
|
||||||
// the copies below should correctly keep copies in sync.
|
// the copies below should correctly keep memory in sync.
|
||||||
//
|
//
|
||||||
// https://sqlite.org/walformat.html#the_wal_index_file_format
|
// https://sqlite.org/walformat.html#the_wal_index_file_format
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ func (s *vfsShm) shmAcquire(ptr *_ErrorCode) {
|
||||||
if ptr != nil && *ptr != _OK {
|
if ptr != nil && *ptr != _OK {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(s.ptrs) == 0 || shmUnmodified(s.shadow[0][:], s.shared[0][:]) {
|
if len(s.ptrs) == 0 || shmEqual(s.shadow[0][:], s.shared[0][:]) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Copies modified words from shared to private memory.
|
// Copies modified words from shared to private memory.
|
||||||
|
@ -53,7 +53,7 @@ func (s *vfsShm) shmAcquire(ptr *_ErrorCode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmRelease() {
|
func (s *vfsShm) shmRelease() {
|
||||||
if len(s.ptrs) == 0 || shmUnmodified(s.shadow[0][:], util.View(s.mod, s.ptrs[0], _WALINDEX_HDR_SIZE)) {
|
if len(s.ptrs) == 0 || shmEqual(s.shadow[0][:], util.View(s.mod, s.ptrs[0], _WALINDEX_HDR_SIZE)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Copies modified words from private to shared memory.
|
// Copies modified words from private to shared memory.
|
||||||
|
@ -82,6 +82,6 @@ func shmPage(s []byte) *[_WALINDEX_PGSZ / 4]uint32 {
|
||||||
return (*[_WALINDEX_PGSZ / 4]uint32)(unsafe.Slice(p, _WALINDEX_PGSZ/4))
|
return (*[_WALINDEX_PGSZ / 4]uint32)(unsafe.Slice(p, _WALINDEX_PGSZ/4))
|
||||||
}
|
}
|
||||||
|
|
||||||
func shmUnmodified(v1, v2 []byte) bool {
|
func shmEqual(v1, v2 []byte) bool {
|
||||||
return *(*[_WALINDEX_HDR_SIZE]byte)(v1[:]) == *(*[_WALINDEX_HDR_SIZE]byte)(v2[:])
|
return *(*[_WALINDEX_HDR_SIZE]byte)(v1[:]) == *(*[_WALINDEX_HDR_SIZE]byte)(v2[:])
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ncruces/go-sqlite3/internal/util"
|
|
||||||
"github.com/tetratelabs/wazero/api"
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
|
||||||
|
"github.com/ncruces/go-sqlite3/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type vfsShmParent struct {
|
type vfsShmParent struct {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build ((freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !sqlite3_nosys) || sqlite3_flock || sqlite3_dotlk
|
//go:build ((freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le)) || sqlite3_flock || sqlite3_dotlk
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build (linux || darwin) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_flock || sqlite3_dotlk || sqlite3_nosys)
|
//go:build (linux || darwin) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_flock || sqlite3_dotlk)
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ type vfsShm struct {
|
||||||
path string
|
path string
|
||||||
regions []*util.MappedRegion
|
regions []*util.MappedRegion
|
||||||
readOnly bool
|
readOnly bool
|
||||||
|
fileLock bool
|
||||||
blocking bool
|
blocking bool
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
@ -29,10 +30,10 @@ var _ blockingSharedMemory = &vfsShm{}
|
||||||
func (s *vfsShm) shmOpen() _ErrorCode {
|
func (s *vfsShm) shmOpen() _ErrorCode {
|
||||||
if s.File == nil {
|
if s.File == nil {
|
||||||
f, err := os.OpenFile(s.path,
|
f, err := os.OpenFile(s.path,
|
||||||
unix.O_RDWR|unix.O_CREAT|unix.O_NOFOLLOW, 0666)
|
os.O_RDWR|os.O_CREATE|_O_NOFOLLOW, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f, err = os.OpenFile(s.path,
|
f, err = os.OpenFile(s.path,
|
||||||
unix.O_RDONLY|unix.O_CREAT|unix.O_NOFOLLOW, 0666)
|
os.O_RDONLY|os.O_CREATE|_O_NOFOLLOW, 0666)
|
||||||
s.readOnly = true
|
s.readOnly = true
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -40,6 +41,9 @@ func (s *vfsShm) shmOpen() _ErrorCode {
|
||||||
}
|
}
|
||||||
s.File = f
|
s.File = f
|
||||||
}
|
}
|
||||||
|
if s.fileLock {
|
||||||
|
return _OK
|
||||||
|
}
|
||||||
|
|
||||||
// Dead man's switch.
|
// Dead man's switch.
|
||||||
if lock, rc := osTestLock(s.File, _SHM_DMS, 1); rc != _OK {
|
if lock, rc := osTestLock(s.File, _SHM_DMS, 1); rc != _OK {
|
||||||
|
@ -64,7 +68,9 @@ func (s *vfsShm) shmOpen() _ErrorCode {
|
||||||
return _IOERR_SHMOPEN
|
return _IOERR_SHMOPEN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return osReadLock(s.File, _SHM_DMS, 1, time.Millisecond)
|
rc := osReadLock(s.File, _SHM_DMS, 1, time.Millisecond)
|
||||||
|
s.fileLock = rc == _OK
|
||||||
|
return rc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, _ErrorCode) {
|
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, _ErrorCode) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build !(((linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !sqlite3_nosys) || sqlite3_flock || sqlite3_dotlk)
|
//go:build !(((linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le)) || sqlite3_flock || sqlite3_dotlk)
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//go:build (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_dotlk || sqlite3_nosys)
|
//go:build (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !sqlite3_dotlk
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tetratelabs/wazero/api"
|
"github.com/tetratelabs/wazero/api"
|
||||||
|
@ -27,6 +28,7 @@ type vfsShm struct {
|
||||||
shadow [][_WALINDEX_PGSZ]byte
|
shadow [][_WALINDEX_PGSZ]byte
|
||||||
ptrs []uint32
|
ptrs []uint32
|
||||||
stack [1]uint64
|
stack [1]uint64
|
||||||
|
fileLock bool
|
||||||
blocking bool
|
blocking bool
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
@ -46,12 +48,16 @@ func (s *vfsShm) Close() error {
|
||||||
|
|
||||||
func (s *vfsShm) shmOpen() _ErrorCode {
|
func (s *vfsShm) shmOpen() _ErrorCode {
|
||||||
if s.File == nil {
|
if s.File == nil {
|
||||||
f, err := osutil.OpenFile(s.path, os.O_RDWR|os.O_CREATE, 0666)
|
f, err := osutil.OpenFile(s.path,
|
||||||
|
os.O_RDWR|os.O_CREATE|syscall.O_NONBLOCK, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return _CANTOPEN
|
return _CANTOPEN
|
||||||
}
|
}
|
||||||
s.File = f
|
s.File = f
|
||||||
}
|
}
|
||||||
|
if s.fileLock {
|
||||||
|
return _OK
|
||||||
|
}
|
||||||
|
|
||||||
// Dead man's switch.
|
// Dead man's switch.
|
||||||
if rc := osWriteLock(s.File, _SHM_DMS, 1, 0); rc == _OK {
|
if rc := osWriteLock(s.File, _SHM_DMS, 1, 0); rc == _OK {
|
||||||
|
@ -61,7 +67,9 @@ func (s *vfsShm) shmOpen() _ErrorCode {
|
||||||
return _IOERR_SHMOPEN
|
return _IOERR_SHMOPEN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return osReadLock(s.File, _SHM_DMS, 1, time.Millisecond)
|
rc := osReadLock(s.File, _SHM_DMS, 1, time.Millisecond)
|
||||||
|
s.fileLock = rc == _OK
|
||||||
|
return rc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (_ uint32, rc _ErrorCode) {
|
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (_ uint32, rc _ErrorCode) {
|
||||||
|
|
|
@ -149,7 +149,7 @@ func (s *ServerConfig) AddHostKey(key Signer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// cachedPubKey contains the results of querying whether a public key is
|
// cachedPubKey contains the results of querying whether a public key is
|
||||||
// acceptable for a user.
|
// acceptable for a user. This is a FIFO cache.
|
||||||
type cachedPubKey struct {
|
type cachedPubKey struct {
|
||||||
user string
|
user string
|
||||||
pubKeyData []byte
|
pubKeyData []byte
|
||||||
|
@ -157,7 +157,13 @@ type cachedPubKey struct {
|
||||||
perms *Permissions
|
perms *Permissions
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxCachedPubKeys = 16
|
// maxCachedPubKeys is the number of cache entries we store.
|
||||||
|
//
|
||||||
|
// Due to consistent misuse of the PublicKeyCallback API, we have reduced this
|
||||||
|
// to 1, such that the only key in the cache is the most recently seen one. This
|
||||||
|
// forces the behavior that the last call to PublicKeyCallback will always be
|
||||||
|
// with the key that is used for authentication.
|
||||||
|
const maxCachedPubKeys = 1
|
||||||
|
|
||||||
// pubKeyCache caches tests for public keys. Since SSH clients
|
// pubKeyCache caches tests for public keys. Since SSH clients
|
||||||
// will query whether a public key is acceptable before attempting to
|
// will query whether a public key is acceptable before attempting to
|
||||||
|
@ -179,9 +185,10 @@ func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) {
|
||||||
|
|
||||||
// add adds the given tuple to the cache.
|
// add adds the given tuple to the cache.
|
||||||
func (c *pubKeyCache) add(candidate cachedPubKey) {
|
func (c *pubKeyCache) add(candidate cachedPubKey) {
|
||||||
if len(c.keys) < maxCachedPubKeys {
|
if len(c.keys) >= maxCachedPubKeys {
|
||||||
c.keys = append(c.keys, candidate)
|
c.keys = c.keys[1:]
|
||||||
}
|
}
|
||||||
|
c.keys = append(c.keys, candidate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConn is an authenticated SSH connection, as seen from the
|
// ServerConn is an authenticated SSH connection, as seen from the
|
||||||
|
|
|
@ -520,7 +520,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.20.3
|
# github.com/ncruces/go-sqlite3 v0.21.0
|
||||||
## 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
|
||||||
|
@ -1069,7 +1069,7 @@ go.uber.org/multierr
|
||||||
# golang.org/x/arch v0.8.0
|
# golang.org/x/arch v0.8.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
golang.org/x/arch/x86/x86asm
|
golang.org/x/arch/x86/x86asm
|
||||||
# golang.org/x/crypto v0.30.0
|
# golang.org/x/crypto v0.31.0
|
||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
golang.org/x/crypto/acme
|
golang.org/x/crypto/acme
|
||||||
golang.org/x/crypto/acme/autocert
|
golang.org/x/crypto/acme/autocert
|
||||||
|
|
Loading…
Reference in New Issue