Limits, and tweaks.

This commit is contained in:
Nuno Cruces
2024-01-18 15:53:00 +00:00
parent 9f58a5d669
commit d998b5f36c
10 changed files with 72 additions and 9 deletions

View File

@@ -113,7 +113,7 @@ with `nolock=1` you must disable connection pooling by calling
### Testing
This project aims for [high test coverage](https://github.com/ncruces/go-sqlite3/wiki/Test-coverage-report).
It also benefits greatly from [SQLite's](https://www.sqlite.org/testing.html) and
It also benefits greatly from [SQLite's](https://sqlite.org/testing.html) and
[wazero's](https://tetrate.io/blog/introducing-wazero-from-tetrate/#:~:text=Rock%2Dsolid%20test%20approach) thorough testing.
The pure Go VFS is tested by running SQLite's

View File

@@ -121,7 +121,7 @@ func (b *Backup) Step(nPage int) (done bool, err error) {
// https://sqlite.org/c3ref/backup_finish.html#sqlite3backupremaining
func (b *Backup) Remaining() int {
r := b.c.call("sqlite3_backup_remaining", uint64(b.handle))
return int(r)
return int(int32(r))
}
// PageCount returns the total number of pages in the source database
@@ -130,5 +130,5 @@ func (b *Backup) Remaining() int {
// https://sqlite.org/c3ref/backup_finish.html#sqlite3backuppagecount
func (b *Backup) PageCount() int {
r := b.c.call("sqlite3_backup_pagecount", uint64(b.handle))
return int(r)
return int(int32(r))
}

View File

@@ -35,7 +35,7 @@ func (c *Conn) Config(op DBConfig, arg ...bool) (bool, error) {
// ConfigLog sets up the error logging callback for the connection.
//
// https://www.sqlite.org/errlog.html
// https://sqlite.org/errlog.html
func (c *Conn) ConfigLog(cb func(code ExtendedErrorCode, msg string)) error {
var enable uint64
if cb != nil {
@@ -55,3 +55,12 @@ func logCallback(ctx context.Context, mod api.Module, _, iCode, zMsg uint32) {
c.log(xErrorCode(iCode), msg)
}
}
// Limit allows the size of various constructs to be
// limited on a connection by connection basis.
//
// https://sqlite.org/c3ref/limit.html
func (c *Conn) Limit(id LimitCategory, value int) int {
r := c.call("sqlite3_limit", uint64(c.handle), uint64(id), uint64(value))
return int(int32(r))
}

View File

@@ -217,7 +217,7 @@ func (c *Conn) ReadOnly(schema string) (ro bool, ok bool) {
ptr = c.arena.string(schema)
}
r := c.call("sqlite3_db_readonly", uint64(c.handle), uint64(ptr))
return int8(r) > 0, int8(r) < 0
return int32(r) > 0, int32(r) < 0
}
// GetAutocommit tests the connection for auto-commit mode.

View File

@@ -229,6 +229,26 @@ const (
DBCONFIG_REVERSE_SCANORDER DBConfig = 1019
)
// LimitCategory are the available run-time limit categories.
//
// https://sqlite.org/c3ref/c_limit_attached.html
type LimitCategory uint32
const (
LIMIT_LENGTH LimitCategory = 0
LIMIT_SQL_LENGTH LimitCategory = 1
LIMIT_COLUMN LimitCategory = 2
LIMIT_EXPR_DEPTH LimitCategory = 3
LIMIT_COMPOUND_SELECT LimitCategory = 4
LIMIT_VDBE_OP LimitCategory = 5
LIMIT_FUNCTION_ARG LimitCategory = 6
LIMIT_ATTACHED LimitCategory = 7
LIMIT_LIKE_PATTERN_LENGTH LimitCategory = 8
LIMIT_VARIABLE_NUMBER LimitCategory = 9
LIMIT_TRIGGER_DEPTH LimitCategory = 10
LIMIT_WORKER_THREADS LimitCategory = 11
)
// TxnState are the allowed return values from [Conn.TxnState].
//
// https://sqlite.org/c3ref/c_txn_none.html

View File

@@ -222,7 +222,7 @@ func (ctx Context) ResultError(err error) {
// VTabNoChange may return true if a column is being fetched as part
// of an update during which the column value will not change.
//
// https://www.sqlite.org/c3ref/vtab_nochange.html
// https://sqlite.org/c3ref/vtab_nochange.html
func (ctx Context) VTabNoChange() bool {
r := ctx.c.call("sqlite3_vtab_nochange", uint64(ctx.handle))
return r != 0

View File

@@ -111,6 +111,9 @@ func (s *Stmt) Exec() error {
//
// https://sqlite.org/c3ref/stmt_status.html
func (s *Stmt) Status(op StmtStatus, reset bool) int {
if op > STMTSTATUS_FILTER_HIT && op != STMTSTATUS_MEMUSED {
return 0
}
var i uint64
if reset {
i = 1

View File

@@ -3,6 +3,7 @@ package tests
import (
"context"
"errors"
"math"
"os"
"path/filepath"
"reflect"
@@ -365,6 +366,36 @@ func TestConn_ConfigLog(t *testing.T) {
}
}
func TestConn_Limit(t *testing.T) {
t.Parallel()
db, err := sqlite3.Open(":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
l := db.Limit(sqlite3.LIMIT_COLUMN, -1)
if l != 2000 {
t.Errorf("got %d, want 2000", l)
}
l = db.Limit(sqlite3.LIMIT_COLUMN, 100)
if l != 2000 {
t.Errorf("got %d, want 2000", l)
}
l = db.Limit(sqlite3.LIMIT_COLUMN, -1)
if l != 100 {
t.Errorf("got %d, want 100", l)
}
l = db.Limit(math.MaxUint32, -1)
if l != -1 {
t.Errorf("got %d, want -1", l)
}
}
func TestConn_ReleaseMemory(t *testing.T) {
t.Parallel()

View File

@@ -204,7 +204,7 @@ func (v Value) NoChange() bool {
// InFirst returns the first element
// on the right-hand side of an IN constraint.
//
// https://www.sqlite.org/c3ref/vtab_in_first.html
// https://sqlite.org/c3ref/vtab_in_first.html
func (v Value) InFirst() (Value, error) {
defer v.c.arena.mark()()
valPtr := v.c.arena.new(ptrlen)
@@ -221,7 +221,7 @@ func (v Value) InFirst() (Value, error) {
// InNext returns the next element
// on the right-hand side of an IN constraint.
//
// https://www.sqlite.org/c3ref/vtab_in_first.html
// https://sqlite.org/c3ref/vtab_in_first.html
func (v Value) InNext() (Value, error) {
defer v.c.arena.mark()()
valPtr := v.c.arena.new(ptrlen)

View File

@@ -78,7 +78,7 @@ func (c *Conn) DeclareVTab(sql string) error {
// VTabConflictMode is a virtual table conflict resolution mode.
//
// https://www.sqlite.org/c3ref/c_fail.html
// https://sqlite.org/c3ref/c_fail.html
type VTabConflictMode uint8
const (