Files
sqlite3/conn.go

202 lines
4.3 KiB
Go
Raw Normal View History

2023-01-12 05:57:09 +00:00
package sqlite3
2023-01-11 14:58:20 +00:00
import (
"context"
)
2023-02-09 16:40:48 +00:00
// Conn is a database connection handle.
//
// https://www.sqlite.org/c3ref/sqlite3.html
2023-01-12 05:57:09 +00:00
type Conn struct {
2023-01-18 12:44:14 +00:00
ctx context.Context
2023-01-12 05:57:09 +00:00
api sqliteAPI
2023-01-28 12:47:39 +00:00
mem memory
handle uint32
2023-01-11 14:58:20 +00:00
}
2023-02-09 16:40:48 +00:00
// Open calls [OpenFlags] with [OPEN_READWRITE] and [OPEN_CREATE].
2023-01-22 15:44:39 +00:00
func Open(filename string) (conn *Conn, err error) {
return OpenFlags(filename, OPEN_READWRITE|OPEN_CREATE)
2023-01-16 12:54:24 +00:00
}
2023-02-09 16:40:48 +00:00
// OpenFlags opens an SQLite database file as specified by the filename argument.
//
// https://www.sqlite.org/c3ref/open.html
2023-01-22 15:44:39 +00:00
func OpenFlags(filename string, flags OpenFlag) (conn *Conn, err error) {
2023-01-18 12:44:14 +00:00
ctx := context.Background()
2023-01-28 12:47:39 +00:00
module, err := sqlite3.instantiateModule(ctx)
2023-01-11 14:58:20 +00:00
if err != nil {
2023-01-12 05:57:09 +00:00
return nil, err
2023-01-11 14:58:20 +00:00
}
2023-01-12 13:43:35 +00:00
defer func() {
if conn == nil {
2023-01-17 13:43:16 +00:00
module.Close(ctx)
2023-01-12 13:43:35 +00:00
}
}()
2023-01-12 05:57:09 +00:00
2023-01-17 13:43:16 +00:00
c := newConn(module)
2023-01-22 17:33:21 +00:00
c.ctx = context.Background()
2023-01-22 15:44:39 +00:00
namePtr := c.newString(filename)
2023-01-25 16:23:18 +00:00
connPtr := c.new(ptrlen)
2023-01-17 13:43:16 +00:00
defer c.free(namePtr)
defer c.free(connPtr)
2023-01-12 13:43:35 +00:00
2023-01-18 12:44:14 +00:00
r, err := c.api.open.Call(c.ctx, uint64(namePtr), uint64(connPtr), uint64(flags), 0)
2023-01-11 14:58:20 +00:00
if err != nil {
2023-01-12 05:57:09 +00:00
return nil, err
2023-01-11 14:58:20 +00:00
}
2023-01-28 12:47:39 +00:00
c.handle = c.mem.readUint32(connPtr)
2023-01-17 13:43:16 +00:00
if err := c.error(r[0]); err != nil {
return nil, err
2023-01-12 05:57:09 +00:00
}
2023-01-17 13:43:16 +00:00
return c, nil
2023-01-12 05:57:09 +00:00
}
2023-02-09 16:40:48 +00:00
// Close closes a database connection.
// If the database connection is associated with unfinalized prepared statements,
// open blob handles, and/or unfinished backup objects,
// Close will leave the database connection open and return [BUSY].
//
// https://www.sqlite.org/c3ref/close.html
2023-01-12 13:43:35 +00:00
func (c *Conn) Close() error {
2023-01-18 12:44:14 +00:00
r, err := c.api.close.Call(c.ctx, uint64(c.handle))
2023-01-12 05:57:09 +00:00
if err != nil {
2023-01-11 14:58:20 +00:00
return err
}
2023-01-12 13:43:35 +00:00
2023-01-17 13:43:16 +00:00
if err := c.error(r[0]); err != nil {
return err
2023-01-12 13:43:35 +00:00
}
2023-01-28 12:47:39 +00:00
return c.mem.mod.Close(c.ctx)
2023-01-11 14:58:20 +00:00
}
2023-02-09 16:40:48 +00:00
// Exec is a convenience function that allows an application to run
// multiple statements of SQL without having to use a lot of code.
//
// https://www.sqlite.org/c3ref/exec.html
2023-01-12 13:43:35 +00:00
func (c *Conn) Exec(sql string) error {
sqlPtr := c.newString(sql)
2023-01-17 13:43:16 +00:00
defer c.free(sqlPtr)
2023-01-12 13:43:35 +00:00
2023-01-18 12:44:14 +00:00
r, err := c.api.exec.Call(c.ctx, uint64(c.handle), uint64(sqlPtr), 0, 0, 0)
2023-01-11 14:58:20 +00:00
if err != nil {
return err
}
2023-01-17 13:43:16 +00:00
return c.error(r[0])
2023-01-11 14:58:20 +00:00
}
2023-02-09 16:40:48 +00:00
// Prepare calls [PrepareFlags] with no flags.
2023-01-16 12:54:24 +00:00
func (c *Conn) Prepare(sql string) (stmt *Stmt, tail string, err error) {
return c.PrepareFlags(sql, 0)
}
2023-02-09 16:40:48 +00:00
// PrepareFlags compiles the first statement in sql;
// tail is left pointing to what remains uncompiled.
// If the input text contains no SQL (if the input is an empty string or a comment),
// both stmt and err will be nil
//
// https://www.sqlite.org/c3ref/exec.html
2023-01-16 12:54:24 +00:00
func (c *Conn) PrepareFlags(sql string, flags PrepareFlag) (stmt *Stmt, tail string, err error) {
2023-01-15 04:35:37 +00:00
sqlPtr := c.newString(sql)
2023-01-25 16:23:18 +00:00
stmtPtr := c.new(ptrlen)
tailPtr := c.new(ptrlen)
2023-01-17 13:43:16 +00:00
defer c.free(sqlPtr)
defer c.free(stmtPtr)
defer c.free(tailPtr)
2023-01-15 04:35:37 +00:00
2023-01-18 12:44:14 +00:00
r, err := c.api.prepare.Call(c.ctx, uint64(c.handle),
2023-01-16 12:54:24 +00:00
uint64(sqlPtr), uint64(len(sql)+1), uint64(flags),
2023-01-15 04:35:37 +00:00
uint64(stmtPtr), uint64(tailPtr))
if err != nil {
return nil, "", err
}
stmt = &Stmt{c: c}
2023-01-28 12:47:39 +00:00
stmt.handle = c.mem.readUint32(stmtPtr)
i := c.mem.readUint32(tailPtr)
2023-01-15 04:35:37 +00:00
tail = sql[i-sqlPtr:]
2023-01-17 13:43:16 +00:00
if err := c.error(r[0]); err != nil {
return nil, "", err
2023-01-15 04:35:37 +00:00
}
if stmt.handle == 0 {
return nil, "", nil
}
return
}
2023-01-17 13:43:16 +00:00
func (c *Conn) error(rc uint64) error {
if rc == _OK {
return nil
}
2023-02-09 16:40:48 +00:00
err := Error{code: rc}
2023-01-12 13:43:35 +00:00
2023-02-09 16:40:48 +00:00
if err.Code() == NOMEM || err.ExtendedCode() == IOERR_NOMEM {
2023-01-21 12:09:54 +00:00
panic(oomErr)
}
2023-01-12 13:43:35 +00:00
var r []uint64
2023-01-21 12:09:54 +00:00
// Do this first, sqlite3_errmsg is guaranteed to never change the value of the error code.
r, _ = c.api.errmsg.Call(c.ctx, uint64(c.handle))
2023-01-12 13:43:35 +00:00
if r != nil {
2023-01-28 12:47:39 +00:00
err.msg = c.mem.readString(uint32(r[0]), 512)
2023-01-12 13:43:35 +00:00
}
2023-01-21 12:09:54 +00:00
r, _ = c.api.errstr.Call(c.ctx, rc)
2023-01-12 13:43:35 +00:00
if r != nil {
2023-01-28 12:47:39 +00:00
err.str = c.mem.readString(uint32(r[0]), 512)
2023-01-12 13:43:35 +00:00
}
2023-01-21 12:09:54 +00:00
if err.msg == err.str {
err.msg = ""
2023-01-12 13:43:35 +00:00
2023-01-21 12:09:54 +00:00
}
return &err
2023-01-12 13:43:35 +00:00
}
2023-01-12 05:57:09 +00:00
func (c *Conn) free(ptr uint32) {
2023-01-12 13:43:35 +00:00
if ptr == 0 {
return
}
2023-01-18 12:44:14 +00:00
_, err := c.api.free.Call(c.ctx, uint64(ptr))
2023-01-11 14:58:20 +00:00
if err != nil {
panic(err)
}
}
2023-01-17 13:43:16 +00:00
func (c *Conn) new(len uint32) uint32 {
2023-01-18 12:44:14 +00:00
r, err := c.api.malloc.Call(c.ctx, uint64(len))
2023-01-11 14:58:20 +00:00
if err != nil {
panic(err)
}
2023-01-25 14:59:02 +00:00
ptr := uint32(r[0])
2023-02-06 01:29:54 +00:00
if ptr == 0 && len != 0 {
2023-01-19 14:31:32 +00:00
panic(oomErr)
2023-01-12 11:06:17 +00:00
}
2023-01-25 14:59:02 +00:00
return ptr
2023-01-11 14:58:20 +00:00
}
2023-01-26 14:52:38 +00:00
func (c *Conn) newBytes(b []byte) uint32 {
if b == nil {
2023-01-17 18:31:46 +00:00
return 0
}
2023-01-11 14:58:20 +00:00
2023-01-26 14:52:38 +00:00
siz := uint32(len(b))
2023-01-17 18:31:46 +00:00
ptr := c.new(siz)
2023-01-29 02:11:41 +00:00
buf := c.mem.view(ptr, siz)
2023-01-26 14:52:38 +00:00
copy(buf, b)
2023-01-17 13:43:16 +00:00
return ptr
}
func (c *Conn) newString(s string) uint32 {
2023-01-17 18:31:46 +00:00
siz := uint32(len(s) + 1)
ptr := c.new(siz)
2023-01-29 02:11:41 +00:00
buf := c.mem.view(ptr, siz)
2023-01-26 14:52:38 +00:00
buf[len(s)] = 0
copy(buf, s)
2023-01-11 14:58:20 +00:00
return ptr
}