mirror of
https://github.com/glebarez/go-sqlite.git
synced 2025-10-08 01:01:02 +08:00
Release the {cgo,VM}-free Linux/Intel version.
modified: Makefile new file: all_linux_test.go renamed: all_test.go -> all_test_windows.go new file: doc.go new file: generate_linux.go new file: generate_windows.go modified: generator.go new file: generator_windows.go modified: internal/bin/bin_linux_386.go modified: internal/bin/bin_linux_amd64.go modified: main.c modified: sqlite.go modified: sqlite_go18.go new file: sqlite_windows.go
This commit is contained in:
4
Makefile
4
Makefile
@@ -29,13 +29,13 @@ cpu: clean
|
|||||||
go tool pprof -lines *.test cpu.out
|
go tool pprof -lines *.test cpu.out
|
||||||
|
|
||||||
edit:
|
edit:
|
||||||
@ 1>/dev/null 2>/dev/null gvim -p Makefile main.c all_test.go sqlite.go
|
@ 1>/dev/null 2>/dev/null gvim -p Makefile main.c *.go
|
||||||
|
|
||||||
editor:
|
editor:
|
||||||
gofmt -l -s -w *.go
|
gofmt -l -s -w *.go
|
||||||
indent -linux *.c
|
indent -linux *.c
|
||||||
|
go test -i
|
||||||
go test 2>&1 | tee log
|
go test 2>&1 | tee log
|
||||||
go build
|
|
||||||
|
|
||||||
internalError:
|
internalError:
|
||||||
egrep -ho '"internal error.*"' *.go | sort | cat -n
|
egrep -ho '"internal error.*"' *.go | sort | cat -n
|
||||||
|
320
all_linux_test.go
Normal file
320
all_linux_test.go
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
// Copyright 2017 The Sqlite Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package sqlite
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"database/sql"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func caller(s string, va ...interface{}) {
|
||||||
|
if s == "" {
|
||||||
|
s = strings.Repeat("%v ", len(va))
|
||||||
|
}
|
||||||
|
_, fn, fl, _ := runtime.Caller(2)
|
||||||
|
fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl)
|
||||||
|
fmt.Fprintf(os.Stderr, s, va...)
|
||||||
|
fmt.Fprintln(os.Stderr)
|
||||||
|
_, fn, fl, _ = runtime.Caller(1)
|
||||||
|
fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl)
|
||||||
|
fmt.Fprintln(os.Stderr)
|
||||||
|
os.Stderr.Sync()
|
||||||
|
}
|
||||||
|
|
||||||
|
func dbg(s string, va ...interface{}) {
|
||||||
|
if s == "" {
|
||||||
|
s = strings.Repeat("%v ", len(va))
|
||||||
|
}
|
||||||
|
_, fn, fl, _ := runtime.Caller(1)
|
||||||
|
fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl)
|
||||||
|
fmt.Fprintf(os.Stderr, s, va...)
|
||||||
|
fmt.Fprintln(os.Stderr)
|
||||||
|
os.Stderr.Sync()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TODO(...interface{}) string { //TODOOK
|
||||||
|
_, fn, fl, _ := runtime.Caller(1)
|
||||||
|
return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK
|
||||||
|
}
|
||||||
|
|
||||||
|
func use(...interface{}) {}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
use(caller, dbg, TODO) //TODOOK
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Add "-tags virtual.profile" to the command.
|
||||||
|
profileAll = flag.Bool("profile", false, "")
|
||||||
|
profileFunctions = flag.Bool("profile_functions", false, "")
|
||||||
|
profileInstructions = flag.Bool("profile_instructions", false, "")
|
||||||
|
profileLines = flag.Bool("profile_lines", false, "")
|
||||||
|
profileRate = flag.Int("profile_rate", 1000, "")
|
||||||
|
recsPerSec = flag.Bool("recs_per_sec_as_mbps", false, "Show records per second as MB/s.")
|
||||||
|
)
|
||||||
|
|
||||||
|
func tempDB(t testing.TB) (string, *sql.DB) {
|
||||||
|
dir, err := ioutil.TempDir("", "sqlite-test-")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := sql.Open(driverName, filepath.Join(dir, "tmp.db"))
|
||||||
|
if err != nil {
|
||||||
|
os.RemoveAll(dir)
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dir, db
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestScalar(t *testing.T) {
|
||||||
|
dir, db := tempDB(t)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
db.Close()
|
||||||
|
os.RemoveAll(dir)
|
||||||
|
}()
|
||||||
|
|
||||||
|
t1 := time.Date(2017, 4, 20, 1, 2, 3, 56789, time.UTC)
|
||||||
|
t2 := time.Date(2018, 5, 21, 2, 3, 4, 98765, time.UTC)
|
||||||
|
r, err := db.Exec(`
|
||||||
|
create table t(i int, f double, b bool, s text, t time);
|
||||||
|
insert into t values(12, 3.14, ?, "foo", ?), (34, 2.78, ?, "bar", ?);
|
||||||
|
`,
|
||||||
|
true, t1,
|
||||||
|
false, t2,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := r.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if g, e := n, int64(2); g != e {
|
||||||
|
t.Fatal(g, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := db.Query("select * from t")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type rec struct {
|
||||||
|
i int
|
||||||
|
f float64
|
||||||
|
b bool
|
||||||
|
s string
|
||||||
|
t string
|
||||||
|
}
|
||||||
|
var a []rec
|
||||||
|
for rows.Next() {
|
||||||
|
var r rec
|
||||||
|
if err := rows.Scan(&r.i, &r.f, &r.b, &r.s, &r.t); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
a = append(a, r)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if g, e := len(a), 2; g != e {
|
||||||
|
t.Fatal(g, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if g, e := a[0], (rec{12, 3.14, true, "foo", t1.String()}); g != e {
|
||||||
|
t.Fatal(g, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if g, e := a[1], (rec{34, 2.78, false, "bar", t2.String()}); g != e {
|
||||||
|
t.Fatal(g, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBlob(t *testing.T) {
|
||||||
|
dir, db := tempDB(t)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
db.Close()
|
||||||
|
os.RemoveAll(dir)
|
||||||
|
}()
|
||||||
|
|
||||||
|
b1 := []byte(time.Now().String())
|
||||||
|
b2 := []byte("\x00foo\x00bar\x00")
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
create table t(b blob);
|
||||||
|
insert into t values(?), (?);
|
||||||
|
`, b1, b2,
|
||||||
|
); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := db.Query("select * from t")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type rec struct {
|
||||||
|
b []byte
|
||||||
|
}
|
||||||
|
var a []rec
|
||||||
|
for rows.Next() {
|
||||||
|
var r rec
|
||||||
|
if err := rows.Scan(&r.b); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
a = append(a, r)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if g, e := len(a), 2; g != e {
|
||||||
|
t.Fatal(g, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if g, e := a[0].b, b1; !bytes.Equal(g, e) {
|
||||||
|
t.Fatal(g, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if g, e := a[1].b, b2; !bytes.Equal(g, e) {
|
||||||
|
t.Fatal(g, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkInsertMemory(b *testing.B) {
|
||||||
|
db, err := sql.Open(driverName, "file::memory:")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
db.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
create table t(i int);
|
||||||
|
begin;
|
||||||
|
`); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := db.Prepare("insert into t values(?)")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if _, err := s.Exec(int64(i)); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.StopTimer()
|
||||||
|
if *recsPerSec {
|
||||||
|
b.SetBytes(1e6)
|
||||||
|
}
|
||||||
|
if _, err := db.Exec(`commit;`); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNextMemory(b *testing.B) {
|
||||||
|
db, err := sql.Open(driverName, "file::memory:")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
db.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
create table t(i int);
|
||||||
|
begin;
|
||||||
|
`); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := db.Prepare("insert into t values(?)")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if _, err := s.Exec(int64(i)); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := db.Exec("commit"); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := db.Query("select * from t")
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if !r.Next() {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.StopTimer()
|
||||||
|
if *recsPerSec {
|
||||||
|
b.SetBytes(1e6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/cznic/sqlite/issues/11
|
||||||
|
func TestIssue11(t *testing.T) {
|
||||||
|
const N = 6570
|
||||||
|
dir, db := tempDB(t)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
db.Close()
|
||||||
|
os.RemoveAll(dir)
|
||||||
|
}()
|
||||||
|
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
CREATE TABLE t1 (t INT);
|
||||||
|
BEGIN;
|
||||||
|
`,
|
||||||
|
); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < N; i++ {
|
||||||
|
if _, err := db.Exec("INSERT INTO t1 (t) VALUES (?)", i); err != nil {
|
||||||
|
t.Fatalf("#%v: %v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := db.Exec("COMMIT;"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
51
doc.go
Normal file
51
doc.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2017 The Sqlite Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package sqlite is an in-process implementation of a self-contained,
|
||||||
|
// serverless, zero-configuration, transactional SQL database engine. (Work In Progress)
|
||||||
|
//
|
||||||
|
// Changelog
|
||||||
|
//
|
||||||
|
// 2017-06-05 Linux/Intel no more uses the VM (cznic/virtual).
|
||||||
|
//
|
||||||
|
// Connecting to a database
|
||||||
|
//
|
||||||
|
// To access a Sqlite database do something like
|
||||||
|
//
|
||||||
|
// import (
|
||||||
|
// "database/sql"
|
||||||
|
//
|
||||||
|
// _ "github.com/cznic/sqlite"
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// ...
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// db, err := sql.Open("sqlite", dsnURI)
|
||||||
|
//
|
||||||
|
// ...
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Do not use in production
|
||||||
|
//
|
||||||
|
// This is an experimental, pre-alpha, technology preview package. Performance
|
||||||
|
// is not (yet) a priority. When this virtual machine approach, hopefully,
|
||||||
|
// reaches a reasonable level of completeness and correctness, the plan is to
|
||||||
|
// eventually mechanically translate the IR form, produced by
|
||||||
|
// http://github.com/cznic/ccir, to Go. Unreadable Go, presumably.
|
||||||
|
//
|
||||||
|
// Even though the translation to Go is now done for Linux/Intel, the package
|
||||||
|
// status is still as described above, it's just closer to the alpha release in
|
||||||
|
// this respect. The alpha release is due when the C runtime support of SQLite
|
||||||
|
// in cznic/crt will be complete.
|
||||||
|
//
|
||||||
|
// Supported platforms and architectures
|
||||||
|
//
|
||||||
|
// See http://github.com/cznic/ccir. To add a newly supported os/arch
|
||||||
|
// combination to this package try running 'go generate'.
|
||||||
|
//
|
||||||
|
// Sqlite documentation
|
||||||
|
//
|
||||||
|
// See https://sqlite.org/docs.html
|
||||||
|
package sqlite
|
7
generate_linux.go
Normal file
7
generate_linux.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// Copyright 2017 The Sqlite Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:generate go run generator.go
|
||||||
|
|
||||||
|
package sqlite
|
7
generate_windows.go
Normal file
7
generate_windows.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// Copyright 2017 The Sqlite Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:generate go run generator_windows.go
|
||||||
|
|
||||||
|
package sqlite
|
218
generator.go
218
generator.go
@@ -8,13 +8,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
|
||||||
"encoding/gob"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/format"
|
"go/format"
|
||||||
"go/scanner"
|
"go/scanner"
|
||||||
"go/token"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@@ -26,11 +23,10 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/cznic/cc"
|
"github.com/cznic/cc"
|
||||||
|
"github.com/cznic/ccgo"
|
||||||
"github.com/cznic/ccir"
|
"github.com/cznic/ccir"
|
||||||
"github.com/cznic/internal/buffer"
|
"github.com/cznic/internal/buffer"
|
||||||
"github.com/cznic/ir"
|
|
||||||
"github.com/cznic/strutil"
|
"github.com/cznic/strutil"
|
||||||
"github.com/cznic/virtual"
|
|
||||||
"github.com/cznic/xc"
|
"github.com/cznic/xc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -46,6 +42,55 @@ var (
|
|||||||
yydebug = flag.Int("yydebug", 0, "")
|
yydebug = flag.Int("yydebug", 0, "")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
prologue = `/*
|
||||||
|
|
||||||
|
%s
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by ccgo DO NOT EDIT.
|
||||||
|
|
||||||
|
package bin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/cznic/crt"
|
||||||
|
"github.com/edsrzf/mmap-go"
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
const minAlloc = 2<<5
|
||||||
|
|
||||||
|
var (
|
||||||
|
inf = math.Inf(1)
|
||||||
|
)
|
||||||
|
|
||||||
|
func ftrace(s string, args ...interface{}) {
|
||||||
|
_, fn, fl, _ := runtime.Caller(1)
|
||||||
|
fmt.Fprintf(os.Stderr, "# %%s:%%d: %%v\n", path.Base(fn), fl, fmt.Sprintf(s, args...))
|
||||||
|
os.Stderr.Sync()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Init(heapSize, heapReserve int) int {
|
||||||
|
heap, err := mmap.MapRegion(nil, heapSize+heapReserve, mmap.RDWR, mmap.ANON, 0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tls := crt.NewTLS()
|
||||||
|
crt.RegisterHeap(unsafe.Pointer(&heap[0]), int64(heapSize+heapReserve))
|
||||||
|
crt.X__register_stdfiles(tls, Xstdin, Xstdout, Xstderr)
|
||||||
|
return int(Xinit(tls, int32(heapSize)))
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
func findRepo(s string) string {
|
func findRepo(s string) string {
|
||||||
s = filepath.FromSlash(s)
|
s = filepath.FromSlash(s)
|
||||||
for _, v := range strings.Split(strutil.Gopath(), string(os.PathListSeparator)) {
|
for _, v := range strings.Split(strutil.Gopath(), string(os.PathListSeparator)) {
|
||||||
@@ -94,32 +139,13 @@ func errStr(err error) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func build(predef string, tus [][]string, opts ...cc.Opt) ([]*cc.TranslationUnit, *virtual.Binary) {
|
func build(predef string, tus [][]string, opts ...cc.Opt) ([]*cc.TranslationUnit, []byte) {
|
||||||
var b buffer.Bytes
|
|
||||||
var lpos token.Position
|
|
||||||
if *cpp {
|
|
||||||
opts = append(opts, cc.Cpp(func(toks []xc.Token) {
|
|
||||||
if len(toks) != 0 {
|
|
||||||
p := toks[0].Position()
|
|
||||||
if p.Filename != lpos.Filename {
|
|
||||||
fmt.Fprintf(&b, "# %d %q\n", p.Line, p.Filename)
|
|
||||||
}
|
|
||||||
lpos = p
|
|
||||||
}
|
|
||||||
for _, v := range toks {
|
|
||||||
b.WriteString(cc.TokSrc(v))
|
|
||||||
}
|
|
||||||
b.WriteByte('\n')
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
ndbg := ""
|
ndbg := ""
|
||||||
if *ndebug {
|
if *ndebug {
|
||||||
ndbg = "#define NDEBUG 1"
|
ndbg = "#define NDEBUG 1"
|
||||||
}
|
}
|
||||||
var build [][]ir.Object
|
var build []*cc.TranslationUnit
|
||||||
tus = append(tus, []string{ccir.CRT0Path})
|
tus = append(tus, []string{ccir.CRT0Path})
|
||||||
var asta []*cc.TranslationUnit
|
|
||||||
for _, src := range tus {
|
for _, src := range tus {
|
||||||
model, err := ccir.NewModel()
|
model, err := ccir.NewModel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -129,6 +155,7 @@ func build(predef string, tus [][]string, opts ...cc.Opt) ([]*cc.TranslationUnit
|
|||||||
ast, err := cc.Parse(
|
ast, err := cc.Parse(
|
||||||
fmt.Sprintf(`
|
fmt.Sprintf(`
|
||||||
%s
|
%s
|
||||||
|
#define _CCGO 1
|
||||||
#define __arch__ %s
|
#define __arch__ %s
|
||||||
#define __os__ %s
|
#define __os__ %s
|
||||||
#include <builtin.h>
|
#include <builtin.h>
|
||||||
@@ -138,79 +165,31 @@ func build(predef string, tus [][]string, opts ...cc.Opt) ([]*cc.TranslationUnit
|
|||||||
model,
|
model,
|
||||||
append([]cc.Opt{
|
append([]cc.Opt{
|
||||||
cc.AllowCompatibleTypedefRedefinitions(),
|
cc.AllowCompatibleTypedefRedefinitions(),
|
||||||
|
cc.EnableEmptyStructs(),
|
||||||
cc.EnableImplicitFuncDef(),
|
cc.EnableImplicitFuncDef(),
|
||||||
cc.EnableNonConstStaticInitExpressions(),
|
cc.EnableNonConstStaticInitExpressions(),
|
||||||
cc.EnableWideBitFieldTypes(),
|
|
||||||
cc.ErrLimit(*errLimit),
|
cc.ErrLimit(*errLimit),
|
||||||
cc.SysIncludePaths([]string{ccir.LibcIncludePath}),
|
cc.SysIncludePaths([]string{ccir.LibcIncludePath}),
|
||||||
}, opts...)...,
|
}, opts...)...,
|
||||||
)
|
)
|
||||||
if s := b.Bytes(); len(s) != 0 {
|
|
||||||
log.Printf("\n%s", s)
|
|
||||||
b.Close()
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(errStr(err))
|
log.Fatal(errStr(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
asta = append(asta, ast)
|
build = append(build, ast)
|
||||||
objs, err := ccir.New(ast)
|
}
|
||||||
if err != nil {
|
|
||||||
|
var out buffer.Bytes
|
||||||
|
if err := ccgo.New(build, &out); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if *oLog {
|
return build, out.Bytes()
|
||||||
for i, v := range objs {
|
|
||||||
switch x := v.(type) {
|
|
||||||
case *ir.DataDefinition:
|
|
||||||
fmt.Fprintf(&b, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Value)
|
|
||||||
case *ir.FunctionDefinition:
|
|
||||||
fmt.Fprintf(&b, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments)
|
|
||||||
for i, v := range x.Body {
|
|
||||||
fmt.Fprintf(&b, "%#05x\t%v\n", i, v)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
log.Fatalf("[%v]: %T %v: %v", i, x, x, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i, v := range objs {
|
|
||||||
if err := v.Verify(); err != nil {
|
|
||||||
switch x := v.(type) {
|
|
||||||
case *ir.FunctionDefinition:
|
|
||||||
fmt.Fprintf(&b, "# [%v, err]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments)
|
|
||||||
for i, v := range x.Body {
|
|
||||||
fmt.Fprintf(&b, "%#05x\t%v\n", i, v)
|
|
||||||
}
|
|
||||||
log.Fatalf("# [%v]: Verify (A): %v\n%s", i, err, b.Bytes())
|
|
||||||
default:
|
|
||||||
log.Fatalf("[%v]: %T %v: %v", i, x, x, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
build = append(build, objs)
|
|
||||||
}
|
|
||||||
|
|
||||||
linked, err := ir.LinkMain(build...)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("ir.LinkMain: %s\n%s", err, b.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range linked {
|
|
||||||
if err := v.Verify(); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bin, err := virtual.LoadMain(linked)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return asta, bin
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func macros(buf io.Writer, ast *cc.TranslationUnit) {
|
func macros(buf io.Writer, ast *cc.TranslationUnit) {
|
||||||
|
fmt.Fprintf(buf, `const (
|
||||||
|
`)
|
||||||
var a []string
|
var a []string
|
||||||
for k, v := range ast.Macros {
|
for k, v := range ast.Macros {
|
||||||
if v.Value != nil && v.Type.Kind() != cc.Bool {
|
if v.Value != nil && v.Type.Kind() != cc.Bool {
|
||||||
@@ -269,6 +248,7 @@ func macros(buf io.Writer, ast *cc.TranslationUnit) {
|
|||||||
dd := ast.Declarations.Identifiers[dict.SID(v)].Node.(*cc.DirectDeclarator)
|
dd := ast.Declarations.Identifiers[dict.SID(v)].Node.(*cc.DirectDeclarator)
|
||||||
fmt.Fprintf(buf, "X%s = %v\n", v, dd.EnumVal)
|
fmt.Fprintf(buf, "X%s = %v\n", v, dd.EnumVal)
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(buf, ")\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -282,10 +262,10 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
asta, bin := build(
|
asta, src := build(
|
||||||
`
|
`
|
||||||
//#define SQLITE_DEBUG 1
|
#define SQLITE_DEBUG 1
|
||||||
//#define SQLITE_ENABLE_API_ARMOR 1
|
#define SQLITE_ENABLE_API_ARMOR 1
|
||||||
#define SQLITE_ENABLE_MEMSYS5 1
|
#define SQLITE_ENABLE_MEMSYS5 1
|
||||||
#define SQLITE_USE_URI 1
|
#define SQLITE_USE_URI 1
|
||||||
`,
|
`,
|
||||||
@@ -297,70 +277,24 @@ func main() {
|
|||||||
cc.IncludePaths([]string{pth}),
|
cc.IncludePaths([]string{pth}),
|
||||||
)
|
)
|
||||||
|
|
||||||
var b0 bytes.Buffer
|
var b bytes.Buffer
|
||||||
enc := gob.NewEncoder(&b0)
|
|
||||||
if err := enc.Encode(&bin); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var b1 bytes.Buffer
|
|
||||||
comp := gzip.NewWriter(&b1)
|
|
||||||
if _, err := comp.Write(b0.Bytes()); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := comp.Close(); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var b2 buffer.Bytes
|
|
||||||
lic, err := ioutil.ReadFile("SQLITE-LICENSE")
|
lic, err := ioutil.ReadFile("SQLITE-LICENSE")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
b2.WriteString(`// Code generated by running "go generate". DO NOT EDIT.
|
fmt.Fprintf(&b, prologue, lic)
|
||||||
|
macros(&b, asta[0])
|
||||||
/*
|
b.Write(src)
|
||||||
|
b2, err := format.Source(b.Bytes())
|
||||||
`)
|
|
||||||
b2.Write(lic)
|
|
||||||
b2.WriteString(`
|
|
||||||
*/
|
|
||||||
|
|
||||||
package bin
|
|
||||||
|
|
||||||
const (
|
|
||||||
`)
|
|
||||||
macros(&b2, asta[0])
|
|
||||||
b2.WriteString(`
|
|
||||||
Data = "`)
|
|
||||||
b := b1.Bytes()
|
|
||||||
for _, v := range b {
|
|
||||||
switch {
|
|
||||||
case v == '\\':
|
|
||||||
b2.WriteString(`\\`)
|
|
||||||
case v == '"':
|
|
||||||
b2.WriteString(`\"`)
|
|
||||||
case v < ' ', v >= 0x7f:
|
|
||||||
fmt.Fprintf(&b2, `\x%02x`, v)
|
|
||||||
default:
|
|
||||||
b2.WriteByte(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b2.WriteString(`"
|
|
||||||
)
|
|
||||||
`)
|
|
||||||
b3, err := format.Source(b2.Bytes())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b3 = b
|
b2 = b.Bytes()
|
||||||
}
|
}
|
||||||
os.MkdirAll("internal/bin", 0775)
|
if err := os.MkdirAll("internal/bin", 0775); err != nil {
|
||||||
if err := ioutil.WriteFile(fmt.Sprintf("internal/bin/bin_%s_%s.go", runtime.GOOS, runtime.GOARCH), b3, 0664); err != nil {
|
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("code %#08x, text %#08x, data %#08x, bss %#08x, pc2func %v, pc2line %v, symbols %v, gz %v\n",
|
if err := ioutil.WriteFile(fmt.Sprintf("internal/bin/bin_%s_%s.go", runtime.GOOS, runtime.GOARCH), b2, 0664); err != nil {
|
||||||
len(bin.Code), len(bin.Text), len(bin.Data), bin.BSS, len(bin.Functions), len(bin.Lines), len(bin.Sym), b1.Len(),
|
log.Fatal(err)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
366
generator_windows.go
Normal file
366
generator_windows.go
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
// Copyright 2017 The Sqlite Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"encoding/gob"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"go/format"
|
||||||
|
"go/scanner"
|
||||||
|
"go/token"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/cznic/cc"
|
||||||
|
"github.com/cznic/ccir"
|
||||||
|
"github.com/cznic/internal/buffer"
|
||||||
|
"github.com/cznic/ir"
|
||||||
|
"github.com/cznic/strutil"
|
||||||
|
"github.com/cznic/virtual"
|
||||||
|
"github.com/cznic/xc"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
cpp = flag.Bool("cpp", false, "")
|
||||||
|
dict = xc.Dict
|
||||||
|
errLimit = flag.Int("errlimit", 10, "")
|
||||||
|
filter = flag.String("re", "", "")
|
||||||
|
ndebug = flag.Bool("ndebug", false, "")
|
||||||
|
noexec = flag.Bool("noexec", false, "")
|
||||||
|
oLog = flag.Bool("log", false, "")
|
||||||
|
trace = flag.Bool("trc", false, "")
|
||||||
|
yydebug = flag.Int("yydebug", 0, "")
|
||||||
|
)
|
||||||
|
|
||||||
|
func findRepo(s string) string {
|
||||||
|
s = filepath.FromSlash(s)
|
||||||
|
for _, v := range strings.Split(strutil.Gopath(), string(os.PathListSeparator)) {
|
||||||
|
p := filepath.Join(v, "src", s)
|
||||||
|
fi, err := os.Lstat(p)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.IsDir() {
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p, err = filepath.Rel(wd, p); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func errStr(err error) string {
|
||||||
|
switch x := err.(type) {
|
||||||
|
case scanner.ErrorList:
|
||||||
|
if len(x) != 1 {
|
||||||
|
x.RemoveMultiples()
|
||||||
|
}
|
||||||
|
var b bytes.Buffer
|
||||||
|
for i, v := range x {
|
||||||
|
if i != 0 {
|
||||||
|
b.WriteByte('\n')
|
||||||
|
}
|
||||||
|
b.WriteString(v.Error())
|
||||||
|
if i == 9 {
|
||||||
|
fmt.Fprintf(&b, "\n\t... and %v more errors", len(x)-10)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
default:
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func build(predef string, tus [][]string, opts ...cc.Opt) ([]*cc.TranslationUnit, *virtual.Binary) {
|
||||||
|
var b buffer.Bytes
|
||||||
|
var lpos token.Position
|
||||||
|
if *cpp {
|
||||||
|
opts = append(opts, cc.Cpp(func(toks []xc.Token) {
|
||||||
|
if len(toks) != 0 {
|
||||||
|
p := toks[0].Position()
|
||||||
|
if p.Filename != lpos.Filename {
|
||||||
|
fmt.Fprintf(&b, "# %d %q\n", p.Line, p.Filename)
|
||||||
|
}
|
||||||
|
lpos = p
|
||||||
|
}
|
||||||
|
for _, v := range toks {
|
||||||
|
b.WriteString(cc.TokSrc(v))
|
||||||
|
}
|
||||||
|
b.WriteByte('\n')
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
ndbg := ""
|
||||||
|
if *ndebug {
|
||||||
|
ndbg = "#define NDEBUG 1"
|
||||||
|
}
|
||||||
|
var build [][]ir.Object
|
||||||
|
tus = append(tus, []string{ccir.CRT0Path})
|
||||||
|
var asta []*cc.TranslationUnit
|
||||||
|
for _, src := range tus {
|
||||||
|
model, err := ccir.NewModel()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ast, err := cc.Parse(
|
||||||
|
fmt.Sprintf(`
|
||||||
|
%s
|
||||||
|
#define __arch__ %s
|
||||||
|
#define __os__ %s
|
||||||
|
#include <builtin.h>
|
||||||
|
%s
|
||||||
|
`, ndbg, runtime.GOARCH, runtime.GOOS, predef),
|
||||||
|
src,
|
||||||
|
model,
|
||||||
|
append([]cc.Opt{
|
||||||
|
cc.AllowCompatibleTypedefRedefinitions(),
|
||||||
|
cc.EnableImplicitFuncDef(),
|
||||||
|
cc.EnableNonConstStaticInitExpressions(),
|
||||||
|
cc.EnableWideBitFieldTypes(),
|
||||||
|
cc.ErrLimit(*errLimit),
|
||||||
|
cc.SysIncludePaths([]string{ccir.LibcIncludePath}),
|
||||||
|
}, opts...)...,
|
||||||
|
)
|
||||||
|
if s := b.Bytes(); len(s) != 0 {
|
||||||
|
log.Printf("\n%s", s)
|
||||||
|
b.Close()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(errStr(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
asta = append(asta, ast)
|
||||||
|
objs, err := ccir.New(ast)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *oLog {
|
||||||
|
for i, v := range objs {
|
||||||
|
switch x := v.(type) {
|
||||||
|
case *ir.DataDefinition:
|
||||||
|
fmt.Fprintf(&b, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Value)
|
||||||
|
case *ir.FunctionDefinition:
|
||||||
|
fmt.Fprintf(&b, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments)
|
||||||
|
for i, v := range x.Body {
|
||||||
|
fmt.Fprintf(&b, "%#05x\t%v\n", i, v)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Fatalf("[%v]: %T %v: %v", i, x, x, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, v := range objs {
|
||||||
|
if err := v.Verify(); err != nil {
|
||||||
|
switch x := v.(type) {
|
||||||
|
case *ir.FunctionDefinition:
|
||||||
|
fmt.Fprintf(&b, "# [%v, err]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments)
|
||||||
|
for i, v := range x.Body {
|
||||||
|
fmt.Fprintf(&b, "%#05x\t%v\n", i, v)
|
||||||
|
}
|
||||||
|
log.Fatalf("# [%v]: Verify (A): %v\n%s", i, err, b.Bytes())
|
||||||
|
default:
|
||||||
|
log.Fatalf("[%v]: %T %v: %v", i, x, x, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
build = append(build, objs)
|
||||||
|
}
|
||||||
|
|
||||||
|
linked, err := ir.LinkMain(build...)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("ir.LinkMain: %s\n%s", err, b.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range linked {
|
||||||
|
if err := v.Verify(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bin, err := virtual.LoadMain(linked)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return asta, bin
|
||||||
|
}
|
||||||
|
|
||||||
|
func macros(buf io.Writer, ast *cc.TranslationUnit) {
|
||||||
|
var a []string
|
||||||
|
for k, v := range ast.Macros {
|
||||||
|
if v.Value != nil && v.Type.Kind() != cc.Bool {
|
||||||
|
switch fn := v.DefTok.Position().Filename; {
|
||||||
|
case
|
||||||
|
fn == "builtin.h",
|
||||||
|
fn == "<predefine>",
|
||||||
|
strings.HasPrefix(fn, "predefined_"):
|
||||||
|
// ignore
|
||||||
|
default:
|
||||||
|
a = append(a, string(dict.S(k)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(a)
|
||||||
|
for _, v := range a {
|
||||||
|
m := ast.Macros[dict.SID(v)]
|
||||||
|
if m.Value == nil {
|
||||||
|
log.Fatal("TODO")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t := m.Type; t.Kind() {
|
||||||
|
case
|
||||||
|
cc.Int, cc.UInt, cc.Long, cc.ULong, cc.LongLong, cc.ULongLong,
|
||||||
|
cc.Float, cc.LongDouble, cc.Bool:
|
||||||
|
fmt.Fprintf(buf, "X%s = %v\n", v, m.Value)
|
||||||
|
case cc.Ptr:
|
||||||
|
switch t := t.Element(); t.Kind() {
|
||||||
|
case cc.Char:
|
||||||
|
fmt.Fprintf(buf, "X%s = %q\n", v, dict.S(int(m.Value.(cc.StringLitID))))
|
||||||
|
default:
|
||||||
|
log.Fatalf("%v", t.Kind())
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Fatalf("%v", t.Kind())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a = a[:0]
|
||||||
|
for _, v := range ast.Declarations.Identifiers {
|
||||||
|
switch x := v.Node.(type) {
|
||||||
|
case *cc.DirectDeclarator:
|
||||||
|
d := x.TopDeclarator()
|
||||||
|
id, _ := d.Identifier()
|
||||||
|
if x.EnumVal == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
a = append(a, string(dict.S(id)))
|
||||||
|
default:
|
||||||
|
log.Fatalf("%T", x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(a)
|
||||||
|
for _, v := range a {
|
||||||
|
dd := ast.Declarations.Identifiers[dict.SID(v)].Node.(*cc.DirectDeclarator)
|
||||||
|
fmt.Fprintf(buf, "X%s = %v\n", v, dd.EnumVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
const repo = "sqlite.org/sqlite-amalgamation-3180000/"
|
||||||
|
|
||||||
|
log.SetFlags(log.Lshortfile | log.Lmicroseconds)
|
||||||
|
flag.Parse()
|
||||||
|
pth := findRepo(repo)
|
||||||
|
if pth == "" {
|
||||||
|
log.Fatalf("repository not found: %v", repo)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
asta, bin := build(
|
||||||
|
`
|
||||||
|
//#define SQLITE_DEBUG 1
|
||||||
|
//#define SQLITE_ENABLE_API_ARMOR 1
|
||||||
|
#define SQLITE_ENABLE_MEMSYS5 1
|
||||||
|
#define SQLITE_USE_URI 1
|
||||||
|
`,
|
||||||
|
[][]string{
|
||||||
|
{"main.c"},
|
||||||
|
{filepath.Join(pth, "sqlite3.c")},
|
||||||
|
},
|
||||||
|
cc.EnableAnonymousStructFields(),
|
||||||
|
cc.IncludePaths([]string{pth}),
|
||||||
|
)
|
||||||
|
|
||||||
|
var b0 bytes.Buffer
|
||||||
|
enc := gob.NewEncoder(&b0)
|
||||||
|
if err := enc.Encode(&bin); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var b1 bytes.Buffer
|
||||||
|
comp := gzip.NewWriter(&b1)
|
||||||
|
if _, err := comp.Write(b0.Bytes()); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := comp.Close(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var b2 buffer.Bytes
|
||||||
|
lic, err := ioutil.ReadFile("SQLITE-LICENSE")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b2.WriteString(`// Code generated by running "go generate". DO NOT EDIT.
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
`)
|
||||||
|
b2.Write(lic)
|
||||||
|
b2.WriteString(`
|
||||||
|
*/
|
||||||
|
|
||||||
|
package bin
|
||||||
|
|
||||||
|
const (
|
||||||
|
`)
|
||||||
|
macros(&b2, asta[0])
|
||||||
|
b2.WriteString(`
|
||||||
|
Data = "`)
|
||||||
|
b := b1.Bytes()
|
||||||
|
for _, v := range b {
|
||||||
|
switch {
|
||||||
|
case v == '\\':
|
||||||
|
b2.WriteString(`\\`)
|
||||||
|
case v == '"':
|
||||||
|
b2.WriteString(`\"`)
|
||||||
|
case v < ' ', v >= 0x7f:
|
||||||
|
fmt.Fprintf(&b2, `\x%02x`, v)
|
||||||
|
default:
|
||||||
|
b2.WriteByte(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b2.WriteString(`"
|
||||||
|
)
|
||||||
|
`)
|
||||||
|
b3, err := format.Source(b2.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
b3 = b
|
||||||
|
}
|
||||||
|
os.MkdirAll("internal/bin", 0775)
|
||||||
|
if err := ioutil.WriteFile(fmt.Sprintf("internal/bin/bin_%s_%s.go", runtime.GOOS, runtime.GOARCH), b3, 0664); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("code %#08x, text %#08x, data %#08x, bss %#08x, pc2func %v, pc2line %v, symbols %v, gz %v\n",
|
||||||
|
len(bin.Code), len(bin.Text), len(bin.Data), bin.BSS, len(bin.Functions), len(bin.Lines), len(bin.Sym), b1.Len(),
|
||||||
|
)
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
44
main.c
44
main.c
@@ -1,30 +1,9 @@
|
|||||||
// +build ignore
|
// Copyright 2017 The Sqlite Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
// SQLite Is Public Domain
|
// SQLite Is Public Domain
|
||||||
//
|
|
||||||
// All of the code and documentation in SQLite has been dedicated to the public
|
// +build ignore
|
||||||
// domain by the authors. All code authors, and representatives of the
|
|
||||||
// companies they work for, have signed affidavits dedicating their
|
|
||||||
// contributions to the public domain and originals of those signed affidavits
|
|
||||||
// are stored in a firesafe at the main offices of Hwaci. Anyone is free to
|
|
||||||
// copy, modify, publish, use, compile, sell, or distribute the original SQLite
|
|
||||||
// code, either in source code form or as a compiled binary, for any purpose,
|
|
||||||
// commercial or non-commercial, and by any means.
|
|
||||||
//
|
|
||||||
// The previous paragraph applies to the deliverable code and documentation in
|
|
||||||
// SQLite - those parts of the SQLite library that you actually bundle and ship
|
|
||||||
// with a larger application. Some scripts used as part of the build process
|
|
||||||
// (for example the "configure" scripts generated by autoconf) might fall under
|
|
||||||
// other open-source licenses. Nothing from these build scripts ever reaches
|
|
||||||
// the final deliverable SQLite library, however, and so the licenses
|
|
||||||
// associated with those scripts should not be a factor in assessing your
|
|
||||||
// rights to copy and use the SQLite library.
|
|
||||||
//
|
|
||||||
// All of the deliverable code in SQLite has been written from scratch. No code
|
|
||||||
// has been taken from other projects or from the open internet. Every line of
|
|
||||||
// code can be traced back to its original author, and all of those authors
|
|
||||||
// have public domain dedications on file. So the SQLite code base is clean and
|
|
||||||
// is uncontaminated with licensed code from other projects.
|
|
||||||
|
|
||||||
#define minAlloc (2<<5)
|
#define minAlloc (2<<5)
|
||||||
|
|
||||||
@@ -33,16 +12,11 @@
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if (argc != 2) {
|
init(-1);
|
||||||
return 1;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int heapSize = 0;
|
|
||||||
char *p = argv[1];
|
|
||||||
for (; *p; p++) {
|
|
||||||
heapSize = 10 * heapSize + *p - '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
int init(int heapSize)
|
||||||
|
{
|
||||||
void *heap = malloc(heapSize);
|
void *heap = malloc(heapSize);
|
||||||
if (heap == 0) {
|
if (heap == 0) {
|
||||||
return 1;
|
return 1;
|
||||||
|
627
sqlite.go
627
sqlite.go
@@ -2,67 +2,24 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:generate go run generator.go
|
|
||||||
|
|
||||||
// Package sqlite is an in-process implementation of a self-contained,
|
|
||||||
// serverless, zero-configuration, transactional SQL database engine. (Work In Progress)
|
|
||||||
//
|
|
||||||
// Connecting to a database
|
|
||||||
//
|
|
||||||
// To access a Sqlite database do something like
|
|
||||||
//
|
|
||||||
// import (
|
|
||||||
// "database/sql"
|
|
||||||
//
|
|
||||||
// _ "github.com/cznic/sqlite"
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// ...
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// db, err := sql.Open("sqlite", dsnURI)
|
|
||||||
//
|
|
||||||
// ...
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Do not use in production
|
|
||||||
//
|
|
||||||
// This is an experimental, pre-alpha, technology preview package. Performance
|
|
||||||
// is not (yet) a priority. When this virtual machine approach, hopefully,
|
|
||||||
// reaches a reasonable level of completeness and correctness, the plan is to
|
|
||||||
// eventually mechanically translate the IR form, produced by
|
|
||||||
// http://github.com/cznic/ccir, to Go. Unreadable Go, presumably.
|
|
||||||
//
|
|
||||||
// Supported platforms and architectures
|
|
||||||
//
|
|
||||||
// See http://github.com/cznic/ccir. To add a newly supported os/arch
|
|
||||||
// combination to this package try running 'go generate'.
|
|
||||||
//
|
|
||||||
// Sqlite documentation
|
|
||||||
//
|
|
||||||
// See https://sqlite.org/docs.html
|
|
||||||
package sqlite
|
package sqlite
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"compress/gzip"
|
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"encoding/gob"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/cznic/crt"
|
||||||
"github.com/cznic/internal/buffer"
|
"github.com/cznic/internal/buffer"
|
||||||
"github.com/cznic/ir"
|
|
||||||
"github.com/cznic/mathutil"
|
"github.com/cznic/mathutil"
|
||||||
"github.com/cznic/sqlite/internal/bin"
|
"github.com/cznic/sqlite/internal/bin"
|
||||||
"github.com/cznic/virtual"
|
|
||||||
"github.com/cznic/xc"
|
"github.com/cznic/xc"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
@@ -76,121 +33,21 @@ var (
|
|||||||
_ driver.Rows = (*rows)(nil)
|
_ driver.Rows = (*rows)(nil)
|
||||||
_ driver.Stmt = (*stmt)(nil)
|
_ driver.Stmt = (*stmt)(nil)
|
||||||
_ driver.Tx = (*tx)(nil)
|
_ driver.Tx = (*tx)(nil)
|
||||||
_ io.Writer = debugWriter{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
driverName = "sqlite"
|
driverName = "sqlite"
|
||||||
ptrSize = mathutil.UintPtrBits / 8
|
ptrSize = mathutil.UintPtrBits / 8
|
||||||
vmHeapReserve = 1 << 20
|
heapReserve = 1 << 20
|
||||||
vmHeapSize = 32 << 20
|
heapSize = 32 << 20
|
||||||
vmMainStackSize = 1 << 16
|
|
||||||
vmStackSize = 1 << 18
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
binary virtual.Binary
|
|
||||||
dict = xc.Dict
|
dict = xc.Dict
|
||||||
null = virtual.Ptr(0)
|
|
||||||
vm *virtual.Machine
|
|
||||||
|
|
||||||
// FFI
|
|
||||||
bindBlob int
|
|
||||||
bindDouble int
|
|
||||||
bindInt int
|
|
||||||
bindInt64 int
|
|
||||||
bindParameterCount int
|
|
||||||
bindParameterName int
|
|
||||||
bindText int
|
|
||||||
changes int
|
|
||||||
closeV2 int
|
|
||||||
columnBlob int
|
|
||||||
columnBytes int
|
|
||||||
columnCount int
|
|
||||||
columnDouble int
|
|
||||||
columnInt64 int
|
|
||||||
columnName int
|
|
||||||
columnText int
|
|
||||||
columnType int
|
|
||||||
errmsg int
|
|
||||||
errstr int
|
|
||||||
exec int
|
|
||||||
extendedResultCodes int
|
|
||||||
finalize int
|
|
||||||
free int
|
|
||||||
interrupt int
|
|
||||||
lastInsertRowID int
|
|
||||||
maloc int
|
|
||||||
openV2 int
|
|
||||||
prepareV2 int
|
|
||||||
step int
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
b0 := bytes.NewBufferString(bin.Data)
|
bin.Init(heapSize, heapReserve)
|
||||||
decomp, err := gzip.NewReader(b0)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var b1 bytes.Buffer
|
|
||||||
chunk := make([]byte, 1<<15)
|
|
||||||
for {
|
|
||||||
n, err := decomp.Read(chunk)
|
|
||||||
b1.Write(chunk[:n])
|
|
||||||
if err != nil {
|
|
||||||
if err != io.EOF {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dec := gob.NewDecoder(&b1)
|
|
||||||
if err := dec.Decode(&binary); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range []struct {
|
|
||||||
*int
|
|
||||||
string
|
|
||||||
}{
|
|
||||||
{&bindBlob, "sqlite3_bind_blob"},
|
|
||||||
{&bindDouble, "sqlite3_bind_double"},
|
|
||||||
{&bindInt, "sqlite3_bind_int"},
|
|
||||||
{&bindInt64, "sqlite3_bind_int64"},
|
|
||||||
{&bindParameterCount, "sqlite3_bind_parameter_count"},
|
|
||||||
{&bindParameterName, "sqlite3_bind_parameter_name"},
|
|
||||||
{&bindText, "sqlite3_bind_text"},
|
|
||||||
{&changes, "sqlite3_changes"},
|
|
||||||
{&closeV2, "sqlite3_close_v2"},
|
|
||||||
{&columnBlob, "sqlite3_column_blob"},
|
|
||||||
{&columnBytes, "sqlite3_column_bytes"},
|
|
||||||
{&columnCount, "sqlite3_column_count"},
|
|
||||||
{&columnDouble, "sqlite3_column_double"},
|
|
||||||
{&columnInt64, "sqlite3_column_int64"},
|
|
||||||
{&columnName, "sqlite3_column_name"},
|
|
||||||
{&columnText, "sqlite3_column_text"},
|
|
||||||
{&columnType, "sqlite3_column_type"},
|
|
||||||
{&errmsg, "sqlite3_errmsg"},
|
|
||||||
{&errstr, "sqlite3_errstr"},
|
|
||||||
{&exec, "sqlite3_exec"},
|
|
||||||
{&extendedResultCodes, "sqlite3_extended_result_codes"},
|
|
||||||
{&finalize, "sqlite3_finalize"},
|
|
||||||
{&free, "sqlite3_free"},
|
|
||||||
{&interrupt, "sqlite3_interrupt"},
|
|
||||||
{&lastInsertRowID, "sqlite3_last_insert_rowid"},
|
|
||||||
{&maloc, "sqlite3_malloc"},
|
|
||||||
{&openV2, "sqlite3_open_v2"},
|
|
||||||
{&prepareV2, "sqlite3_prepare_v2"},
|
|
||||||
{&step, "sqlite3_step"},
|
|
||||||
} {
|
|
||||||
var ok bool
|
|
||||||
if *v.int, ok = binary.Sym[ir.NameID(dict.SID(v.string))]; !ok {
|
|
||||||
panic(fmt.Errorf("missing symbol: %v", v.string))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sql.Register(driverName, newDrv())
|
sql.Register(driverName, newDrv())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,13 +60,6 @@ func tracer(rx interface{}, format string, args ...interface{}) {
|
|||||||
b.Close()
|
b.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func readI8(p uintptr) int8 { return *(*int8)(unsafe.Pointer(p)) }
|
|
||||||
func readPtr(p uintptr) uintptr { return *(*uintptr)(unsafe.Pointer(p)) }
|
|
||||||
|
|
||||||
type debugWriter struct{}
|
|
||||||
|
|
||||||
func (debugWriter) Write(b []byte) (int, error) { return os.Stderr.Write(b) }
|
|
||||||
|
|
||||||
type result struct {
|
type result struct {
|
||||||
*stmt
|
*stmt
|
||||||
lastInsertId int64
|
lastInsertId int64
|
||||||
@@ -235,23 +85,13 @@ func newResult(s *stmt) (_ *result, err error) {
|
|||||||
|
|
||||||
// sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
|
// sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
|
||||||
func (r *result) lastInsertRowID() (v int64, _ error) {
|
func (r *result) lastInsertRowID() (v int64, _ error) {
|
||||||
_, err := r.FFI1(
|
return bin.Xsqlite3_last_insert_rowid(r.tls, r.pdb()), nil
|
||||||
lastInsertRowID,
|
|
||||||
virtual.Int64Result{&v},
|
|
||||||
virtual.Ptr(r.pdb()),
|
|
||||||
)
|
|
||||||
return v, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// int sqlite3_changes(sqlite3*);
|
// int sqlite3_changes(sqlite3*);
|
||||||
func (r *result) changes() (int, error) {
|
func (r *result) changes() (int, error) {
|
||||||
var v int32
|
v := bin.Xsqlite3_changes(r.tls, r.pdb())
|
||||||
_, err := r.FFI1(
|
return int(v), nil
|
||||||
changes,
|
|
||||||
virtual.Int32Result{&v},
|
|
||||||
virtual.Ptr(r.pdb()),
|
|
||||||
)
|
|
||||||
return int(v), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LastInsertId returns the database's auto-generated ID after, for example, an
|
// LastInsertId returns the database's auto-generated ID after, for example, an
|
||||||
@@ -277,7 +117,7 @@ type rows struct {
|
|||||||
*stmt
|
*stmt
|
||||||
columns []string
|
columns []string
|
||||||
rc0 int
|
rc0 int
|
||||||
pstmt uintptr
|
pstmt unsafe.Pointer
|
||||||
doStep bool
|
doStep bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +125,7 @@ func (r *rows) String() string {
|
|||||||
return fmt.Sprintf("&%T@%p{stmt: %p, columns: %v, rc0: %v, pstmt: %#x, doStep: %v}", *r, r, r.stmt, r.columns, r.rc0, r.pstmt, r.doStep)
|
return fmt.Sprintf("&%T@%p{stmt: %p, columns: %v, rc0: %v, pstmt: %#x, doStep: %v}", *r, r, r.stmt, r.columns, r.rc0, r.pstmt, r.doStep)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRows(s *stmt, pstmt uintptr, rc0 int) (*rows, error) {
|
func newRows(s *stmt, pstmt unsafe.Pointer, rc0 int) (*rows, error) {
|
||||||
r := &rows{
|
r := &rows{
|
||||||
stmt: s,
|
stmt: s,
|
||||||
pstmt: pstmt,
|
pstmt: pstmt,
|
||||||
@@ -405,118 +245,68 @@ func (r *rows) Next(dest []driver.Value) (err error) {
|
|||||||
|
|
||||||
// int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
|
// int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
|
||||||
func (r *rows) columnBytes(iCol int) (_ int, err error) {
|
func (r *rows) columnBytes(iCol int) (_ int, err error) {
|
||||||
var v int32
|
v := bin.Xsqlite3_column_bytes(r.tls, r.pstmt, int32(iCol))
|
||||||
if _, err = r.FFI1(
|
return int(v), nil
|
||||||
columnBytes,
|
|
||||||
virtual.Int32Result{&v},
|
|
||||||
virtual.Ptr(r.pstmt), virtual.Int32(iCol),
|
|
||||||
); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return int(v), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
|
// const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
|
||||||
func (r *rows) columnBlob(iCol int) (v []byte, err error) {
|
func (r *rows) columnBlob(iCol int) (v []byte, err error) {
|
||||||
var p uintptr
|
p := bin.Xsqlite3_column_blob(r.tls, r.pstmt, int32(iCol))
|
||||||
if _, err = r.FFI1(
|
|
||||||
columnBlob,
|
|
||||||
virtual.PtrResult{&p},
|
|
||||||
virtual.Ptr(r.pstmt), virtual.Int32(iCol),
|
|
||||||
); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
len, err := r.columnBytes(iCol)
|
len, err := r.columnBytes(iCol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return virtual.GoBytesLen(p, len), nil
|
return crt.GoBytesLen((*int8)(p), len), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
|
// const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
|
||||||
func (r *rows) columnText(iCol int) (v string, err error) {
|
func (r *rows) columnText(iCol int) (v string, err error) {
|
||||||
var p uintptr
|
p := bin.Xsqlite3_column_text(r.tls, r.pstmt, int32(iCol))
|
||||||
if _, err = r.FFI1(
|
|
||||||
columnText,
|
|
||||||
virtual.PtrResult{&p},
|
|
||||||
virtual.Ptr(r.pstmt), virtual.Int32(iCol),
|
|
||||||
); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
len, err := r.columnBytes(iCol)
|
len, err := r.columnBytes(iCol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return virtual.GoStringLen(p, len), nil
|
return crt.GoStringLen((*int8)(unsafe.Pointer(p)), len), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// double sqlite3_column_double(sqlite3_stmt*, int iCol);
|
// double sqlite3_column_double(sqlite3_stmt*, int iCol);
|
||||||
func (r *rows) columnDouble(iCol int) (v float64, err error) {
|
func (r *rows) columnDouble(iCol int) (v float64, err error) {
|
||||||
_, err = r.FFI1(
|
v = bin.Xsqlite3_column_double(r.tls, r.pstmt, int32(iCol))
|
||||||
columnDouble,
|
return v, nil
|
||||||
virtual.Float64Result{&v},
|
|
||||||
virtual.Ptr(r.pstmt), virtual.Int32(iCol),
|
|
||||||
)
|
|
||||||
return v, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
|
// sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
|
||||||
func (r *rows) columnInt64(iCol int) (v int64, err error) {
|
func (r *rows) columnInt64(iCol int) (v int64, err error) {
|
||||||
_, err = r.FFI1(
|
v = bin.Xsqlite3_column_int64(r.tls, r.pstmt, int32(iCol))
|
||||||
columnInt64,
|
return v, nil
|
||||||
virtual.Int64Result{&v},
|
|
||||||
virtual.Ptr(r.pstmt), virtual.Int32(iCol),
|
|
||||||
)
|
|
||||||
return v, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// int sqlite3_column_type(sqlite3_stmt*, int iCol);
|
// int sqlite3_column_type(sqlite3_stmt*, int iCol);
|
||||||
func (r *rows) columnType(iCol int) (_ int, err error) {
|
func (r *rows) columnType(iCol int) (_ int, err error) {
|
||||||
var v int32
|
v := bin.Xsqlite3_column_type(r.tls, r.pstmt, int32(iCol))
|
||||||
_, err = r.FFI1(
|
return int(v), nil
|
||||||
columnType,
|
|
||||||
virtual.Int32Result{&v},
|
|
||||||
virtual.Ptr(r.pstmt), virtual.Int32(iCol),
|
|
||||||
)
|
|
||||||
return int(v), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// int sqlite3_column_count(sqlite3_stmt *pStmt);
|
// int sqlite3_column_count(sqlite3_stmt *pStmt);
|
||||||
func (r *rows) columnCount() (_ int, err error) {
|
func (r *rows) columnCount() (_ int, err error) {
|
||||||
var v int32
|
v := bin.Xsqlite3_column_count(r.tls, r.pstmt)
|
||||||
_, err = r.FFI1(
|
return int(v), nil
|
||||||
columnCount,
|
|
||||||
virtual.Int32Result{&v},
|
|
||||||
virtual.Ptr(r.pstmt),
|
|
||||||
)
|
|
||||||
return int(v), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// const char *sqlite3_column_name(sqlite3_stmt*, int N);
|
// const char *sqlite3_column_name(sqlite3_stmt*, int N);
|
||||||
func (r *rows) columnName(n int) (string, error) {
|
func (r *rows) columnName(n int) (string, error) {
|
||||||
var p uintptr
|
p := bin.Xsqlite3_column_name(r.tls, r.pstmt, int32(n))
|
||||||
if _, err := r.FFI1(
|
return crt.GoString(p), nil
|
||||||
columnName,
|
|
||||||
virtual.PtrResult{&p},
|
|
||||||
virtual.Ptr(r.pstmt), virtual.Int32(n),
|
|
||||||
); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return virtual.GoString(p), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type stmt struct {
|
type stmt struct {
|
||||||
*conn
|
*conn
|
||||||
allocs []uintptr
|
allocs []unsafe.Pointer
|
||||||
psql uintptr
|
psql *int8
|
||||||
ppstmt uintptr
|
ppstmt *unsafe.Pointer
|
||||||
pzTail uintptr
|
pzTail **int8
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stmt) String() string {
|
func (s *stmt) String() string {
|
||||||
@@ -533,19 +323,19 @@ func newStmt(c *conn, sql string) (*stmt, error) {
|
|||||||
s.psql = psql
|
s.psql = psql
|
||||||
ppstmt, err := s.malloc(ptrSize)
|
ppstmt, err := s.malloc(ptrSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.free(psql)
|
s.free(unsafe.Pointer(psql))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.ppstmt = ppstmt
|
s.ppstmt = (*unsafe.Pointer)(ppstmt)
|
||||||
pzTail, err := s.malloc(ptrSize)
|
pzTail, err := s.malloc(ptrSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.free(psql)
|
s.free(unsafe.Pointer(psql))
|
||||||
s.free(ppstmt)
|
s.free(ppstmt)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.pzTail = pzTail
|
s.pzTail = (**int8)(pzTail)
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,21 +348,21 @@ func (s *stmt) Close() (err error) {
|
|||||||
tracer(s, "Close(): %v", err)
|
tracer(s, "Close(): %v", err)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
if s.psql != 0 {
|
if s.psql != nil {
|
||||||
err = s.free(s.psql)
|
err = s.free(unsafe.Pointer(s.psql))
|
||||||
s.psql = 0
|
s.psql = nil
|
||||||
}
|
}
|
||||||
if s.ppstmt != 0 {
|
if s.ppstmt != nil {
|
||||||
if err2 := s.free(s.ppstmt); err2 != nil && err == nil {
|
if err2 := s.free(unsafe.Pointer(s.ppstmt)); err2 != nil && err == nil {
|
||||||
err = err2
|
err = err2
|
||||||
}
|
}
|
||||||
s.ppstmt = 0
|
s.ppstmt = nil
|
||||||
}
|
}
|
||||||
if s.pzTail != 0 {
|
if s.pzTail != nil {
|
||||||
if err2 := s.free(s.pzTail); err2 != nil && err == nil {
|
if err2 := s.free(unsafe.Pointer(s.pzTail)); err2 != nil && err == nil {
|
||||||
err = err2
|
err = err2
|
||||||
}
|
}
|
||||||
s.pzTail = 0
|
s.pzTail = nil
|
||||||
}
|
}
|
||||||
for _, v := range s.allocs {
|
for _, v := range s.allocs {
|
||||||
if err2 := s.free(v); err2 != nil && err == nil {
|
if err2 := s.free(v); err2 != nil && err == nil {
|
||||||
@@ -613,27 +403,27 @@ func (s *stmt) exec(ctx context.Context, args []namedValue) (r driver.Result, er
|
|||||||
}(args)
|
}(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
var pstmt uintptr
|
var pstmt unsafe.Pointer
|
||||||
|
|
||||||
donech := make(chan struct{})
|
donech := make(chan struct{})
|
||||||
defer close(donech)
|
defer close(donech)
|
||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
if pstmt != 0 {
|
if pstmt != nil {
|
||||||
s.interrupt(s.pdb())
|
s.interrupt(s.pdb())
|
||||||
}
|
}
|
||||||
case <-donech:
|
case <-donech:
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for psql := s.psql; readI8(psql) != 0; psql = readPtr(s.pzTail) {
|
for psql := s.psql; *psql != 0; psql = *s.pzTail {
|
||||||
if err := s.prepareV2(psql); err != nil {
|
if err := s.prepareV2(psql); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pstmt = readPtr(s.ppstmt)
|
pstmt = *s.ppstmt
|
||||||
if pstmt == 0 {
|
if pstmt == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,8 +469,7 @@ func (s *stmt) query(ctx context.Context, args []namedValue) (r driver.Rows, err
|
|||||||
}(args)
|
}(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
var pstmt uintptr
|
var pstmt, rowStmt unsafe.Pointer
|
||||||
var rowStmt uintptr
|
|
||||||
var rc0 int
|
var rc0 int
|
||||||
|
|
||||||
donech := make(chan struct{})
|
donech := make(chan struct{})
|
||||||
@@ -688,20 +477,20 @@ func (s *stmt) query(ctx context.Context, args []namedValue) (r driver.Rows, err
|
|||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
if pstmt != 0 {
|
if pstmt != nil {
|
||||||
s.interrupt(s.pdb())
|
s.interrupt(s.pdb())
|
||||||
}
|
}
|
||||||
case <-donech:
|
case <-donech:
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for psql := s.psql; readI8(psql) != 0; psql = readPtr(s.pzTail) {
|
for psql := s.psql; *psql != 0; psql = *s.pzTail {
|
||||||
if err := s.prepareV2(psql); err != nil {
|
if err := s.prepareV2(psql); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pstmt = readPtr(s.ppstmt)
|
pstmt = *s.ppstmt
|
||||||
if pstmt == 0 {
|
if pstmt == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -724,7 +513,7 @@ func (s *stmt) query(ctx context.Context, args []namedValue) (r driver.Rows, err
|
|||||||
|
|
||||||
switch rc {
|
switch rc {
|
||||||
case bin.XSQLITE_ROW:
|
case bin.XSQLITE_ROW:
|
||||||
if rowStmt != 0 {
|
if rowStmt != nil {
|
||||||
if err := s.finalize(pstmt); err != nil {
|
if err := s.finalize(pstmt); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -735,7 +524,7 @@ func (s *stmt) query(ctx context.Context, args []namedValue) (r driver.Rows, err
|
|||||||
rowStmt = pstmt
|
rowStmt = pstmt
|
||||||
rc0 = rc
|
rc0 = rc
|
||||||
case bin.XSQLITE_DONE:
|
case bin.XSQLITE_DONE:
|
||||||
if rowStmt == 0 {
|
if rowStmt == nil {
|
||||||
rc0 = rc
|
rc0 = rc
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -748,17 +537,8 @@ func (s *stmt) query(ctx context.Context, args []namedValue) (r driver.Rows, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// int sqlite3_bind_double(sqlite3_stmt*, int, double);
|
// int sqlite3_bind_double(sqlite3_stmt*, int, double);
|
||||||
func (s *stmt) bindDouble(pstmt uintptr, idx1 int, value float64) (err error) {
|
func (s *stmt) bindDouble(pstmt unsafe.Pointer, idx1 int, value float64) (err error) {
|
||||||
var rc int32
|
if rc := bin.Xsqlite3_bind_double(s.tls, pstmt, int32(idx1), value); rc != 0 {
|
||||||
if _, err = s.FFI1(
|
|
||||||
bindDouble,
|
|
||||||
virtual.Int32Result{&rc},
|
|
||||||
virtual.Ptr(pstmt), virtual.Int32(int32(idx1)), virtual.Float64(value),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rc != bin.XSQLITE_OK {
|
|
||||||
return s.errstr(rc)
|
return s.errstr(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,17 +546,8 @@ func (s *stmt) bindDouble(pstmt uintptr, idx1 int, value float64) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// int sqlite3_bind_int(sqlite3_stmt*, int, int);
|
// int sqlite3_bind_int(sqlite3_stmt*, int, int);
|
||||||
func (s *stmt) bindInt(pstmt uintptr, idx1, value int) (err error) {
|
func (s *stmt) bindInt(pstmt unsafe.Pointer, idx1, value int) (err error) {
|
||||||
var rc int32
|
if rc := bin.Xsqlite3_bind_int(s.tls, pstmt, int32(idx1), int32(value)); rc != bin.XSQLITE_OK {
|
||||||
if _, err = s.FFI1(
|
|
||||||
bindInt,
|
|
||||||
virtual.Int32Result{&rc},
|
|
||||||
virtual.Ptr(pstmt), virtual.Int32(int32(idx1)), virtual.Int32(int32(value)),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rc != bin.XSQLITE_OK {
|
|
||||||
return s.errstr(rc)
|
return s.errstr(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -784,17 +555,8 @@ func (s *stmt) bindInt(pstmt uintptr, idx1, value int) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
|
// int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
|
||||||
func (s *stmt) bindInt64(pstmt uintptr, idx1 int, value int64) (err error) {
|
func (s *stmt) bindInt64(pstmt unsafe.Pointer, idx1 int, value int64) (err error) {
|
||||||
var rc int32
|
if rc := bin.Xsqlite3_bind_int64(s.tls, pstmt, int32(idx1), value); rc != bin.XSQLITE_OK {
|
||||||
if _, err = s.FFI1(
|
|
||||||
bindInt64,
|
|
||||||
virtual.Int32Result{&rc},
|
|
||||||
virtual.Ptr(pstmt), virtual.Int32(int32(idx1)), virtual.Int64(value),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rc != bin.XSQLITE_OK {
|
|
||||||
return s.errstr(rc)
|
return s.errstr(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -802,24 +564,15 @@ func (s *stmt) bindInt64(pstmt uintptr, idx1 int, value int64) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
|
// int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
|
||||||
func (s *stmt) bindBlob(pstmt uintptr, idx1 int, value []byte) (err error) {
|
func (s *stmt) bindBlob(pstmt unsafe.Pointer, idx1 int, value []byte) (err error) {
|
||||||
p, err := s.malloc(len(value))
|
p, err := s.malloc(len(value))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.allocs = append(s.allocs, p)
|
s.allocs = append(s.allocs, p)
|
||||||
virtual.CopyBytes(p, value, false)
|
crt.CopyBytes(p, value, false)
|
||||||
var rc int32
|
if rc := bin.Xsqlite3_bind_blob(s.tls, pstmt, int32(idx1), p, int32(len(value)), nil); rc != bin.XSQLITE_OK {
|
||||||
if _, err = s.FFI1(
|
|
||||||
bindBlob,
|
|
||||||
virtual.Int32Result{&rc},
|
|
||||||
virtual.Ptr(pstmt), virtual.Int32(int32(idx1)), virtual.Ptr(p), virtual.Int32(int32(len(value))), null,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rc != bin.XSQLITE_OK {
|
|
||||||
return s.errstr(rc)
|
return s.errstr(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,30 +580,21 @@ func (s *stmt) bindBlob(pstmt uintptr, idx1 int, value []byte) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
|
// int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
|
||||||
func (s *stmt) bindText(pstmt uintptr, idx1 int, value string) (err error) {
|
func (s *stmt) bindText(pstmt unsafe.Pointer, idx1 int, value string) (err error) {
|
||||||
p, err := s.cString(value)
|
p, err := s.cString(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.allocs = append(s.allocs, p)
|
s.allocs = append(s.allocs, unsafe.Pointer(p))
|
||||||
var rc int32
|
if rc := bin.Xsqlite3_bind_text(s.tls, pstmt, int32(idx1), p, int32(len(value)), nil); rc != bin.XSQLITE_OK {
|
||||||
if _, err = s.FFI1(
|
|
||||||
bindText,
|
|
||||||
virtual.Int32Result{&rc},
|
|
||||||
virtual.Ptr(pstmt), virtual.Int32(int32(idx1)), virtual.Ptr(p), virtual.Int32(int32(len(value))), null,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rc != bin.XSQLITE_OK {
|
|
||||||
return s.errstr(rc)
|
return s.errstr(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stmt) bind(pstmt uintptr, n int, args []namedValue) error {
|
func (s *stmt) bind(pstmt unsafe.Pointer, n int, args []namedValue) error {
|
||||||
for i := 1; i <= n; i++ {
|
for i := 1; i <= n; i++ {
|
||||||
name, err := s.bindParameterName(pstmt, i)
|
name, err := s.bindParameterName(pstmt, i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -878,9 +622,9 @@ func (s *stmt) bind(pstmt uintptr, n int, args []namedValue) error {
|
|||||||
if v.Ordinal == 0 {
|
if v.Ordinal == 0 {
|
||||||
if name != "" {
|
if name != "" {
|
||||||
return fmt.Errorf("missing named argument %q", name[1:])
|
return fmt.Errorf("missing named argument %q", name[1:])
|
||||||
} else {
|
|
||||||
return fmt.Errorf("missing argument with %d index", i)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("missing argument with %d index", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch x := v.Value.(type) {
|
switch x := v.Value.(type) {
|
||||||
@@ -920,40 +664,20 @@ func (s *stmt) bind(pstmt uintptr, n int, args []namedValue) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// int sqlite3_bind_parameter_count(sqlite3_stmt*);
|
// int sqlite3_bind_parameter_count(sqlite3_stmt*);
|
||||||
func (s *stmt) bindParameterCount(pstmt uintptr) (_ int, err error) {
|
func (s *stmt) bindParameterCount(pstmt unsafe.Pointer) (_ int, err error) {
|
||||||
var r int32
|
r := bin.Xsqlite3_bind_parameter_count(s.tls, pstmt)
|
||||||
_, err = s.FFI1(
|
return int(r), nil
|
||||||
bindParameterCount,
|
|
||||||
virtual.Int32Result{&r},
|
|
||||||
virtual.Ptr(pstmt),
|
|
||||||
)
|
|
||||||
return int(r), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
|
// const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
|
||||||
func (s *stmt) bindParameterName(pstmt uintptr, i int) (string, error) {
|
func (s *stmt) bindParameterName(pstmt unsafe.Pointer, i int) (string, error) {
|
||||||
var p uintptr
|
p := bin.Xsqlite3_bind_parameter_name(s.tls, pstmt, int32(i))
|
||||||
_, err := s.FFI1(
|
return crt.GoString(p), nil
|
||||||
bindParameterName,
|
|
||||||
virtual.PtrResult{&p},
|
|
||||||
virtual.Ptr(pstmt),
|
|
||||||
virtual.Int32(i),
|
|
||||||
)
|
|
||||||
return virtual.GoString(p), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// int sqlite3_finalize(sqlite3_stmt *pStmt);
|
// int sqlite3_finalize(sqlite3_stmt *pStmt);
|
||||||
func (s *stmt) finalize(pstmt uintptr) error {
|
func (s *stmt) finalize(pstmt unsafe.Pointer) error {
|
||||||
var rc int32
|
if rc := bin.Xsqlite3_finalize(s.tls, pstmt); rc != bin.XSQLITE_OK {
|
||||||
if _, err := s.FFI1(
|
|
||||||
finalize,
|
|
||||||
virtual.Int32Result{&rc},
|
|
||||||
virtual.Ptr(pstmt),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rc != bin.XSQLITE_OK {
|
|
||||||
return s.errstr(rc)
|
return s.errstr(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -961,14 +685,9 @@ func (s *stmt) finalize(pstmt uintptr) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// int sqlite3_step(sqlite3_stmt*);
|
// int sqlite3_step(sqlite3_stmt*);
|
||||||
func (s *stmt) step(pstmt uintptr) (int, error) {
|
func (s *stmt) step(pstmt unsafe.Pointer) (int, error) {
|
||||||
var rc int32
|
r := bin.Xsqlite3_step(s.tls, pstmt)
|
||||||
_, err := s.FFI1(
|
return int(r), nil
|
||||||
step,
|
|
||||||
virtual.Int32Result{&rc},
|
|
||||||
virtual.Ptr(pstmt),
|
|
||||||
)
|
|
||||||
return int(rc), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// int sqlite3_prepare_v2(
|
// int sqlite3_prepare_v2(
|
||||||
@@ -978,17 +697,8 @@ func (s *stmt) step(pstmt uintptr) (int, error) {
|
|||||||
// sqlite3_stmt **ppStmt, /* OUT: Statement handle */
|
// sqlite3_stmt **ppStmt, /* OUT: Statement handle */
|
||||||
// const char **pzTail /* OUT: Pointer to unused portion of zSql */
|
// const char **pzTail /* OUT: Pointer to unused portion of zSql */
|
||||||
// );
|
// );
|
||||||
func (s *stmt) prepareV2(zSql uintptr) error {
|
func (s *stmt) prepareV2(zSql *int8) error {
|
||||||
var rc int32
|
if rc := bin.Xsqlite3_prepare_v2(s.tls, s.pdb(), zSql, -1, s.ppstmt, s.pzTail); rc != bin.XSQLITE_OK {
|
||||||
if _, err := s.FFI1(
|
|
||||||
prepareV2,
|
|
||||||
virtual.Int32Result{&rc},
|
|
||||||
virtual.Ptr(s.pdb()), virtual.Ptr(zSql), virtual.Int32(-1), virtual.Ptr(s.ppstmt), virtual.Ptr(s.pzTail),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rc != bin.XSQLITE_OK {
|
|
||||||
return s.errstr(rc)
|
return s.errstr(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1043,7 +753,7 @@ func (t *tx) exec(ctx context.Context, sql string) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer t.free(psql)
|
defer t.free(unsafe.Pointer(psql))
|
||||||
|
|
||||||
// TODO: use t.conn.ExecContext() instead
|
// TODO: use t.conn.ExecContext() instead
|
||||||
donech := make(chan struct{})
|
donech := make(chan struct{})
|
||||||
@@ -1056,16 +766,7 @@ func (t *tx) exec(ctx context.Context, sql string) (err error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var rc int32
|
if rc := bin.Xsqlite3_exec(t.tls, t.pdb(), psql, nil, nil, nil); rc != bin.XSQLITE_OK {
|
||||||
if _, err = t.FFI1(
|
|
||||||
exec,
|
|
||||||
virtual.Int32Result{&rc},
|
|
||||||
virtual.Ptr(t.pdb()), virtual.Ptr(psql), null, null, null,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rc != bin.XSQLITE_OK {
|
|
||||||
return t.errstr(rc)
|
return t.errstr(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1074,12 +775,12 @@ func (t *tx) exec(ctx context.Context, sql string) (err error) {
|
|||||||
|
|
||||||
type conn struct {
|
type conn struct {
|
||||||
*Driver
|
*Driver
|
||||||
*virtual.Thread
|
ppdb **bin.Xsqlite3
|
||||||
ppdb uintptr
|
tls *crt.TLS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) String() string {
|
func (c *conn) String() string {
|
||||||
return fmt.Sprintf("&%T@%p{sqlite: %p, Thread: %p, ppdb: %#x}", *c, c, c.Driver, c.Thread, c.ppdb)
|
return fmt.Sprintf("&%T@%p{sqlite: %p, Thread: %p, ppdb: %#x}", *c, c, c.Driver, c.tls, c.ppdb)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newConn(s *Driver, name string) (_ *conn, err error) {
|
func newConn(s *Driver, name string) (_ *conn, err error) {
|
||||||
@@ -1095,24 +796,7 @@ func newConn(s *Driver, name string) (_ *conn, err error) {
|
|||||||
|
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
|
||||||
c.conns++
|
c.tls = crt.NewTLS()
|
||||||
if c.conns == 1 {
|
|
||||||
stderr := ioutil.Discard
|
|
||||||
if trace {
|
|
||||||
stderr = debugWriter{}
|
|
||||||
}
|
|
||||||
m, status, err2 := virtual.New(&binary, []string{"", fmt.Sprint(vmHeapSize - vmHeapReserve)}, nil, nil, stderr, vmHeapSize, vmMainStackSize, "")
|
|
||||||
if status != 0 || err2 != nil {
|
|
||||||
return nil, fmt.Errorf("virtual.New: %v, %v", status, err2)
|
|
||||||
}
|
|
||||||
|
|
||||||
vm = m
|
|
||||||
}
|
|
||||||
c.Thread, err = vm.NewThread(vmStackSize)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = c.openV2(
|
if err = c.openV2(
|
||||||
name,
|
name,
|
||||||
bin.XSQLITE_OPEN_READWRITE|bin.XSQLITE_OPEN_CREATE|
|
bin.XSQLITE_OPEN_READWRITE|bin.XSQLITE_OPEN_CREATE|
|
||||||
@@ -1255,23 +939,15 @@ func (c *conn) query(ctx context.Context, query string, args []namedValue) (r dr
|
|||||||
return s.(*stmt).query(ctx, args)
|
return s.(*stmt).query(ctx, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) pdb() uintptr { return readPtr(c.ppdb) }
|
func (c *conn) pdb() *bin.Xsqlite3 { return *c.ppdb }
|
||||||
|
|
||||||
// int sqlite3_extended_result_codes(sqlite3*, int onoff);
|
// int sqlite3_extended_result_codes(sqlite3*, int onoff);
|
||||||
func (c *conn) extendedResultCodes(on bool) (err error) {
|
func (c *conn) extendedResultCodes(on bool) (err error) {
|
||||||
var v, rc int32
|
var v int32
|
||||||
if on {
|
if on {
|
||||||
v = 1
|
v = 1
|
||||||
}
|
}
|
||||||
if _, err = c.FFI1(
|
if rc := bin.Xsqlite3_extended_result_codes(c.tls, c.pdb(), v); rc != bin.XSQLITE_OK {
|
||||||
extendedResultCodes,
|
|
||||||
virtual.Int32Result{&rc},
|
|
||||||
virtual.Ptr(c.pdb()), virtual.Int32(v),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rc != bin.XSQLITE_OK {
|
|
||||||
return c.errstr(rc)
|
return c.errstr(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1279,23 +955,28 @@ func (c *conn) extendedResultCodes(on bool) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// void *sqlite3_malloc(int);
|
// void *sqlite3_malloc(int);
|
||||||
func (c *conn) malloc(n int) (r uintptr, err error) {
|
func (c *conn) malloc(n int) (r unsafe.Pointer, err error) {
|
||||||
_, err = c.FFI1(
|
if n > math.MaxInt32 {
|
||||||
maloc,
|
panic("internal error")
|
||||||
virtual.PtrResult{&r},
|
|
||||||
virtual.Int32(int32(n)),
|
|
||||||
)
|
|
||||||
return r, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *conn) cString(s string) (p uintptr, err error) {
|
|
||||||
n := len(s)
|
|
||||||
if p, err = c.malloc(n + 1); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual.CopyString(p, s, true)
|
r = bin.Xsqlite3_malloc(c.tls, int32(n))
|
||||||
return p, nil
|
if r == nil {
|
||||||
|
return nil, fmt.Errorf("malloc(%v) failed", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *conn) cString(s string) (*int8, error) {
|
||||||
|
n := len(s)
|
||||||
|
p, err := c.malloc(n + 1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
crt.CopyString(p, s, true)
|
||||||
|
return (*int8)(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// int sqlite3_open_v2(
|
// int sqlite3_open_v2(
|
||||||
@@ -1310,24 +991,15 @@ func (c *conn) openV2(name string, flags int32) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer c.free(filename)
|
defer c.free(unsafe.Pointer(filename))
|
||||||
|
|
||||||
ppdb, err := c.malloc(ptrSize)
|
ppdb, err := c.malloc(ptrSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ppdb = ppdb
|
c.ppdb = (**bin.Xsqlite3)(ppdb)
|
||||||
var rc int32
|
if rc := bin.Xsqlite3_open_v2(c.tls, filename, c.ppdb, flags, nil); rc != bin.XSQLITE_OK {
|
||||||
if _, err = c.FFI1(
|
|
||||||
openV2,
|
|
||||||
virtual.Int32Result{&rc},
|
|
||||||
virtual.Ptr(filename), virtual.Ptr(ppdb), virtual.Int32(flags), null,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rc != bin.XSQLITE_OK {
|
|
||||||
return c.errstr(rc)
|
return c.errstr(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1336,25 +1008,11 @@ func (c *conn) openV2(name string, flags int32) error {
|
|||||||
|
|
||||||
// const char *sqlite3_errstr(int);
|
// const char *sqlite3_errstr(int);
|
||||||
func (c *conn) errstr(rc int32) (err error) {
|
func (c *conn) errstr(rc int32) (err error) {
|
||||||
var p uintptr
|
p := bin.Xsqlite3_errstr(c.tls, rc)
|
||||||
if _, err = c.FFI1(
|
str := crt.GoString(p)
|
||||||
errstr,
|
p = bin.Xsqlite3_errmsg(c.tls, c.pdb())
|
||||||
virtual.PtrResult{&p},
|
|
||||||
virtual.Int32(rc),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
str := virtual.GoString(p)
|
switch msg := crt.GoString(p); {
|
||||||
if _, err = c.FFI1(
|
|
||||||
errmsg,
|
|
||||||
virtual.PtrResult{&p},
|
|
||||||
virtual.Ptr(c.pdb()),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch msg := virtual.GoString(p); {
|
|
||||||
case msg == str:
|
case msg == str:
|
||||||
return fmt.Errorf("%s (%v)", str, rc)
|
return fmt.Errorf("%s (%v)", str, rc)
|
||||||
default:
|
default:
|
||||||
@@ -1364,64 +1022,39 @@ func (c *conn) errstr(rc int32) (err error) {
|
|||||||
|
|
||||||
// int sqlite3_close_v2(sqlite3*);
|
// int sqlite3_close_v2(sqlite3*);
|
||||||
func (c *conn) closeV2() (err error) {
|
func (c *conn) closeV2() (err error) {
|
||||||
var rc int32
|
if rc := bin.Xsqlite3_close_v2(c.tls, c.pdb()); rc != bin.XSQLITE_OK {
|
||||||
if _, err = c.FFI1(
|
|
||||||
closeV2,
|
|
||||||
virtual.Int32Result{&rc},
|
|
||||||
virtual.Ptr(c.pdb()),
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rc != bin.XSQLITE_OK {
|
|
||||||
return c.errstr(rc)
|
return c.errstr(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.free(c.ppdb)
|
err = c.free(unsafe.Pointer(c.ppdb))
|
||||||
c.ppdb = 0
|
c.ppdb = nil
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// void sqlite3_free(void*);
|
// void sqlite3_free(void*);
|
||||||
func (c *conn) free(p uintptr) (err error) {
|
func (c *conn) free(p unsafe.Pointer) (err error) {
|
||||||
_, err = c.FFI0(
|
bin.Xsqlite3_free(c.tls, p)
|
||||||
free,
|
return nil
|
||||||
virtual.Ptr(p),
|
|
||||||
)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// void sqlite3_interrupt(sqlite3*);
|
// void sqlite3_interrupt(sqlite3*);
|
||||||
func (c *conn) interrupt(pdb uintptr) (err error) {
|
func (c *conn) interrupt(pdb *bin.Xsqlite3) (err error) {
|
||||||
_, err = c.FFI0(
|
bin.Xsqlite3_interrupt(c.tls, pdb)
|
||||||
interrupt,
|
return nil
|
||||||
virtual.Ptr(pdb),
|
|
||||||
)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) close() (err error) {
|
func (c *conn) close() (err error) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
|
|
||||||
defer func() {
|
defer c.Unlock()
|
||||||
c.conns--
|
|
||||||
if c.conns == 0 {
|
|
||||||
if err2 := vm.Close(); err2 != nil && err == nil {
|
|
||||||
err = err2
|
|
||||||
}
|
|
||||||
vm = nil
|
|
||||||
}
|
|
||||||
c.Unlock()
|
|
||||||
}()
|
|
||||||
|
|
||||||
if c.ppdb != 0 {
|
if c.ppdb != nil {
|
||||||
err = c.closeV2()
|
err = c.closeV2()
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
conns int
|
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"errors"
|
"errors"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ping implements driver.Pinger
|
// Ping implements driver.Pinger
|
||||||
@@ -17,7 +18,7 @@ func (c *conn) Ping(ctx context.Context) error {
|
|||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
|
||||||
if c.ppdb == 0 {
|
if uintptr(unsafe.Pointer(c.ppdb)) == 0 {
|
||||||
return errors.New("db is closed")
|
return errors.New("db is closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1406
sqlite_windows.go
Normal file
1406
sqlite_windows.go
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user