From cd40213898bd417896b6c8c5f407e1069f1c294d Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Mon, 4 Dec 2023 12:37:53 +0000 Subject: [PATCH] Reuse statement, API. --- const.go | 20 +++++++++- driver/driver.go | 23 +++++------ embed/exports.txt | 2 + embed/sqlite3.wasm | Bin 1469775 -> 1470030 bytes ext/csv/csv.go | 4 +- ext/lines/lines.go | 2 +- ext/statement/stmt.go | 90 ++++++++++++++++++++++-------------------- func.go | 7 +++- stmt.go | 50 +++++++++++++++++------ tests/stmt_test.go | 4 ++ vfs/os_std_access.go | 18 ++++----- vtab.go | 7 +++- 12 files changed, 144 insertions(+), 83 deletions(-) diff --git a/const.go b/const.go index 5697b31c..5c46934f 100644 --- a/const.go +++ b/const.go @@ -169,7 +169,8 @@ const ( PREPARE_NO_VTAB PrepareFlag = 0x04 ) -// FunctionFlag is a flag that can be passed to [Conn.PrepareFlags]. +// FunctionFlag is a flag that can be passed to +// [Conn.CreateFunction] and [Conn.CreateWindowFunction]. // // https://sqlite.org/c3ref/c_deterministic.html type FunctionFlag uint32 @@ -181,6 +182,23 @@ const ( INNOCUOUS FunctionFlag = 0x000200000 ) +// StmtStatus name counter values associated with the [Stmt.Status] method. +// +// https://sqlite.org/c3ref/c_stmtstatus_counter.html +type StmtStatus uint32 + +const ( + STMTSTATUS_FULLSCAN_STEP StmtStatus = 1 + STMTSTATUS_SORT StmtStatus = 2 + STMTSTATUS_AUTOINDEX StmtStatus = 3 + STMTSTATUS_VM_STEP StmtStatus = 4 + STMTSTATUS_REPREPARE StmtStatus = 5 + STMTSTATUS_RUN StmtStatus = 6 + STMTSTATUS_FILTER_MISS StmtStatus = 7 + STMTSTATUS_FILTER_HIT StmtStatus = 8 + STMTSTATUS_MEMUSED StmtStatus = 99 +) + // Datatype is a fundamental datatype of SQLite. // // https://sqlite.org/c3ref/c_blob.html diff --git a/driver/driver.go b/driver/driver.go index 564786c6..ef08aa76 100644 --- a/driver/driver.go +++ b/driver/driver.go @@ -250,7 +250,7 @@ func (c *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, e s.Close() return nil, util.TailErr } - return &stmt{s, c.Conn}, nil + return &stmt{s}, nil } func (c *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { @@ -281,8 +281,7 @@ func (*conn) CheckNamedValue(arg *driver.NamedValue) error { } type stmt struct { - Stmt *sqlite3.Stmt - Conn *sqlite3.Conn + *sqlite3.Stmt } var ( @@ -292,10 +291,6 @@ var ( _ driver.NamedValueChecker = &stmt{} ) -func (s *stmt) Close() error { - return s.Stmt.Close() -} - func (s *stmt) NumInput() int { n := s.Stmt.BindCount() for i := 1; i <= n; i++ { @@ -322,15 +317,15 @@ func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (drive return nil, err } - old := s.Conn.SetInterrupt(ctx) - defer s.Conn.SetInterrupt(old) + old := s.Stmt.Conn().SetInterrupt(ctx) + defer s.Stmt.Conn().SetInterrupt(old) err = s.Stmt.Exec() if err != nil { return nil, err } - return newResult(s.Conn), nil + return newResult(s.Stmt.Conn()), nil } func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { @@ -338,7 +333,7 @@ func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driv if err != nil { return nil, err } - return &rows{ctx, s.Stmt, s.Conn}, nil + return &rows{ctx, s.Stmt}, nil } func (s *stmt) setupBindings(args []driver.NamedValue) error { @@ -442,10 +437,10 @@ func (r resultRowsAffected) RowsAffected() (int64, error) { type rows struct { ctx context.Context Stmt *sqlite3.Stmt - Conn *sqlite3.Conn } func (r *rows) Close() error { + r.Stmt.ClearBindings() return r.Stmt.Reset() } @@ -469,8 +464,8 @@ func (r *rows) ColumnTypeDatabaseTypeName(index int) string { } func (r *rows) Next(dest []driver.Value) error { - old := r.Conn.SetInterrupt(r.ctx) - defer r.Conn.SetInterrupt(old) + old := r.Stmt.Conn().SetInterrupt(r.ctx) + defer r.Stmt.Conn().SetInterrupt(old) if !r.Stmt.Step() { if err := r.Stmt.Err(); err != nil { diff --git a/embed/exports.txt b/embed/exports.txt index 88310f08..ddd284db 100644 --- a/embed/exports.txt +++ b/embed/exports.txt @@ -74,7 +74,9 @@ sqlite3_result_value sqlite3_result_zeroblob64 sqlite3_set_auxdata_go sqlite3_step +sqlite3_stmt_busy sqlite3_stmt_readonly +sqlite3_stmt_status sqlite3_uri_key sqlite3_uri_parameter sqlite3_user_data diff --git a/embed/sqlite3.wasm b/embed/sqlite3.wasm index 47c4d106b25e8346d176cde83647ea5deabc9a15..3f519dc6ae2e9b6a3621b7911498ad6421162c25 100755 GIT binary patch delta 23239 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 a3o7>nI}mmACK#6zZ}0mWenB`p|NjHuRKT48 diff --git a/ext/csv/csv.go b/ext/csv/csv.go index 87d173d9..4910f25b 100644 --- a/ext/csv/csv.go +++ b/ext/csv/csv.go @@ -172,9 +172,9 @@ func (t *table) newReader() *csv.Reader { type cursor struct { table *table - rowID int64 - row []string csv *csv.Reader + row []string + rowID int64 } func (c *cursor) Filter(idxNum int, idxStr string, arg ...sqlite3.Value) error { diff --git a/ext/lines/lines.go b/ext/lines/lines.go index 638715e0..1f7e360d 100644 --- a/ext/lines/lines.go +++ b/ext/lines/lines.go @@ -52,11 +52,11 @@ func (l lines) Open() (sqlite3.VTabCursor, error) { } type cursor struct { - reader bool scanner *bufio.Scanner closer io.Closer rowID int64 eof bool + reader bool } func (c *cursor) Close() (err error) { diff --git a/ext/statement/stmt.go b/ext/statement/stmt.go index 55d5df28..81ef4e31 100644 --- a/ext/statement/stmt.go +++ b/ext/statement/stmt.go @@ -26,12 +26,10 @@ func Register(db *sqlite3.Conn) { sql = sql[1 : len-1] } - table := &table{ - db: db, - sql: sql, - } - err = table.declare() + table := &table{sql: sql} + err = table.declare(db) if err != nil { + table.Close() return nil, err } return table, nil @@ -41,42 +39,40 @@ func Register(db *sqlite3.Conn) { } type table struct { - db *sqlite3.Conn - sql string - inputs int - outputs int + stmt *sqlite3.Stmt + sql string + inuse bool } -func (t *table) declare() error { - stmt, tail, err := t.db.Prepare(t.sql) +func (t *table) declare(db *sqlite3.Conn) (err error) { + var tail string + t.stmt, tail, err = db.Prepare(t.sql) if err != nil { return err } - defer stmt.Close() if tail != "" { return fmt.Errorf("statement: multiple statements") } - if !stmt.ReadOnly() { + if !t.stmt.ReadOnly() { return fmt.Errorf("statement: statement must be read only") } - t.inputs = stmt.BindCount() - t.outputs = stmt.ColumnCount() - var sep = "" var str strings.Builder str.WriteString(`CREATE TABLE x(`) - for i := 0; i < t.outputs; i++ { + outputs := t.stmt.ColumnCount() + for i := 0; i < outputs; i++ { str.WriteString(sep) - name := stmt.ColumnName(i) + name := t.stmt.ColumnName(i) str.WriteString(sqlite3.QuoteIdentifier(name)) str.WriteByte(' ') - str.WriteString(stmt.ColumnDeclType(i)) + str.WriteString(t.stmt.ColumnDeclType(i)) sep = "," } - for i := 1; i <= t.inputs; i++ { + inputs := t.stmt.BindCount() + for i := 1; i <= inputs; i++ { str.WriteString(sep) - name := stmt.BindName(i) + name := t.stmt.BindName(i) if name == "" { str.WriteString("[") str.WriteString(strconv.Itoa(i)) @@ -87,22 +83,24 @@ func (t *table) declare() error { } sep = "," } - str.WriteByte(')') - return t.db.DeclareVtab(str.String()) + return db.DeclareVtab(str.String()) +} + +func (t *table) Close() error { + return t.stmt.Close() } func (t *table) BestIndex(idx *sqlite3.IndexInfo) error { - idx.OrderByConsumed = false - idx.EstimatedCost = 1 - idx.EstimatedRows = 1 + idx.EstimatedCost = 1000 var argvIndex = 1 var needIndex bool var listIndex []int + outputs := t.stmt.ColumnCount() for i, cst := range idx.Constraint { // Skip if this is a constraint on one of our output columns. - if cst.Column < t.outputs { + if cst.Column < outputs { continue } @@ -114,7 +112,7 @@ func (t *table) BestIndex(idx *sqlite3.IndexInfo) error { // The non-zero argvIdx values must be contiguous. // If they're not, build a list and serialize it through IdxStr. - nextIndex := cst.Column - t.outputs + 1 + nextIndex := cst.Column - outputs + 1 idx.ConstraintUsage[i] = sqlite3.IndexConstraintUsage{ ArgvIndex: argvIndex, Omit: true, @@ -136,10 +134,15 @@ func (t *table) BestIndex(idx *sqlite3.IndexInfo) error { return nil } -func (t *table) Open() (sqlite3.VTabCursor, error) { - stmt, _, err := t.db.Prepare(t.sql) - if err != nil { - return nil, err +func (t *table) Open() (_ sqlite3.VTabCursor, err error) { + stmt := t.stmt + if !t.inuse { + t.inuse = true + } else { + stmt, _, err = t.stmt.Conn().Prepare(t.sql) + if err != nil { + return nil, err + } } return &cursor{table: t, stmt: stmt}, nil } @@ -153,26 +156,29 @@ type cursor struct { stmt *sqlite3.Stmt arg []sqlite3.Value rowID int64 - done bool } func (c *cursor) Close() error { + if c.stmt == c.table.stmt { + c.table.inuse = false + c.stmt.ClearBindings() + return c.stmt.Reset() + } return c.stmt.Close() } func (c *cursor) Filter(idxNum int, idxStr string, arg ...sqlite3.Value) error { c.arg = arg c.rowID = 0 - if err := c.stmt.ClearBindings(); err != nil { - return err - } + c.stmt.ClearBindings() if err := c.stmt.Reset(); err != nil { return err } var list []int if idxStr != "" { - err := json.Unmarshal([]byte(idxStr), &list) + buf := unsafe.Slice(unsafe.StringData(idxStr), len(idxStr)) + err := json.Unmarshal(buf, &list) if err != nil { return err } @@ -196,12 +202,11 @@ func (c *cursor) Next() error { c.rowID++ return nil } - c.done = true return c.stmt.Err() } func (c *cursor) EOF() bool { - return c.done + return !c.stmt.Busy() } func (c *cursor) RowID() (int64, error) { @@ -209,10 +214,11 @@ func (c *cursor) RowID() (int64, error) { } func (c *cursor) Column(ctx *sqlite3.Context, col int) error { - if col < c.table.outputs { + switch outputs := c.stmt.ColumnCount(); { + case col < outputs: ctx.ResultValue(c.stmt.ColumnValue(col)) - } else if col-c.table.outputs < len(c.arg) { - ctx.ResultValue(c.arg[col-c.table.outputs]) + case col-outputs < len(c.arg): + ctx.ResultValue(c.arg[col-outputs]) } return nil } diff --git a/func.go b/func.go index 2a8b5e4a..fbf0812d 100644 --- a/func.go +++ b/func.go @@ -32,7 +32,7 @@ func (c *Conn) CreateCollation(name string, fn func(a, b []byte) int) error { // CreateFunction defines a new scalar SQL function. // // 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 ScalarFunction) error { defer c.arena.mark()() namePtr := c.arena.string(name) funcPtr := util.AddHandle(c.ctx, fn) @@ -42,6 +42,9 @@ func (c *Conn) CreateFunction(name string, nArg int, flag FunctionFlag, fn func( return c.error(r) } +// ScalarFunction is the type of a scalar SQL function. +type ScalarFunction func(ctx Context, arg ...Value) + // CreateWindowFunction defines a new aggregate or aggregate window SQL function. // If fn returns a [WindowFunction], then an aggregate window function is created. // If fn returns an [io.Closer], it will be called to free resources. @@ -95,7 +98,7 @@ func compareCallback(ctx context.Context, mod api.Module, pApp, nKey1, pKey1, nK func funcCallback(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) { db := ctx.Value(connKey{}).(*Conn) - fn := userDataHandle(db, pCtx).(func(ctx Context, arg ...Value)) + fn := userDataHandle(db, pCtx).(ScalarFunction) fn(Context{db, pCtx}, callbackArgs(db, nArg, pArg)...) } diff --git a/stmt.go b/stmt.go index 3f5da0d0..85ac4479 100644 --- a/stmt.go +++ b/stmt.go @@ -34,6 +34,22 @@ func (s *Stmt) Close() error { return s.c.error(r) } +// Conn returns the database connection to which the prepared statement belongs. +// +// https://sqlite.org/c3ref/db_handle.html +func (s *Stmt) Conn() *Conn { + return s.c +} + +// ReadOnly returns true if and only if the statement +// makes no direct changes to the content of the database file. +// +// https://sqlite.org/c3ref/stmt_readonly.html +func (s *Stmt) ReadOnly() bool { + r := s.c.call("sqlite3_stmt_readonly", uint64(s.handle)) + return r != 0 +} + // Reset resets the prepared statement object. // // https://sqlite.org/c3ref/reset.html @@ -43,12 +59,12 @@ func (s *Stmt) Reset() error { return s.c.error(r) } -// ClearBindings resets all bindings on the prepared statement. +// Busy determines if a prepared statement has been reset. // -// https://sqlite.org/c3ref/clear_bindings.html -func (s *Stmt) ClearBindings() error { - r := s.c.call("sqlite3_clear_bindings", uint64(s.handle)) - return s.c.error(r) +// https://sqlite.org/c3ref/stmt_busy.html +func (s *Stmt) Busy() bool { + r := s.c.call("sqlite3_stmt_busy", uint64(s.handle)) + return r != 0 } // Step evaluates the SQL statement. @@ -90,13 +106,25 @@ func (s *Stmt) Exec() error { return s.Reset() } -// ReadOnly returns true if and only if the statement -// makes no direct changes to the content of the database file. +// Status monitors the performance characteristics of prepared statements. // -// https://sqlite.org/c3ref/stmt_readonly.html -func (s *Stmt) ReadOnly() bool { - r := s.c.call("sqlite3_stmt_readonly", uint64(s.handle)) - return r != 0 +// https://sqlite.org/c3ref/stmt_status.html +func (s *Stmt) Status(op StmtStatus, reset bool) int { + var i uint64 + if reset { + i = 1 + } + r := s.c.call("sqlite3_stmt_status", uint64(s.handle), + uint64(op), i) + return int(r) +} + +// ClearBindings resets all bindings on the prepared statement. +// +// https://sqlite.org/c3ref/clear_bindings.html +func (s *Stmt) ClearBindings() error { + r := s.c.call("sqlite3_clear_bindings", uint64(s.handle)) + return s.c.error(r) } // BindCount returns the number of SQL parameters in the prepared statement. diff --git a/tests/stmt_test.go b/tests/stmt_test.go index c475f232..a39acc78 100644 --- a/tests/stmt_test.go +++ b/tests/stmt_test.go @@ -586,6 +586,10 @@ func TestStmt_ColumnTime(t *testing.T) { t.Errorf("want error") } } + + if got := stmt.Status(sqlite3.STMTSTATUS_RUN, true); got != 1 { + t.Errorf("got %d, want 1", got) + } } func TestStmt_Error(t *testing.T) { diff --git a/vfs/os_std_access.go b/vfs/os_std_access.go index b1ca611a..1621c099 100644 --- a/vfs/os_std_access.go +++ b/vfs/os_std_access.go @@ -7,12 +7,6 @@ import ( "os" ) -const ( - _S_IREAD = 0400 - _S_IWRITE = 0200 - _S_IEXEC = 0100 -) - func osAccess(path string, flags AccessFlag) error { fi, err := os.Stat(path) if err != nil { @@ -22,12 +16,18 @@ func osAccess(path string, flags AccessFlag) error { return nil } - var want fs.FileMode = _S_IREAD + const ( + S_IREAD = 0400 + S_IWRITE = 0200 + S_IEXEC = 0100 + ) + + var want fs.FileMode = S_IREAD if flags == ACCESS_READWRITE { - want |= _S_IWRITE + want |= S_IWRITE } if fi.IsDir() { - want |= _S_IEXEC + want |= S_IEXEC } if fi.Mode()&want != want { return fs.ErrPermission diff --git a/vtab.go b/vtab.go index 928a6d9c..f5bddf7e 100644 --- a/vtab.go +++ b/vtab.go @@ -143,7 +143,7 @@ type VTabRenamer interface { type VTabOverloader interface { VTab // https://sqlite.org/vtab.html#xfindfunction - FindFunction(arg int, name string) (func(ctx Context, arg ...Value), IndexConstraintOp) + FindFunction(arg int, name string) (ScalarFunction, IndexConstraintOp) } // A VTabChecker allows a virtual table to report errors @@ -161,6 +161,11 @@ type VTabChecker interface { // A VTabTx allows a virtual table to implement // transactions with two-phase commit. +// +// Anything that is required as part of a commit that may fail +// should be performed in the Sync() callback. +// Current versions of SQLite ignore any errors +// returned by Commit() and Rollback(). type VTabTx interface { VTab // https://sqlite.org/vtab.html#xBegin