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:
Jan Mercl
2017-06-05 20:13:10 +02:00
parent 1a3b0a731a
commit 8c183b526b
14 changed files with 343809 additions and 686 deletions

View File

@@ -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
View 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
View 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
View 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
View 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

View File

@@ -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 {
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...) var out buffer.Bytes
if err != nil { if err := ccgo.New(build, &out); 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) log.Fatal(err)
} }
return asta, bin return build, out.Bytes()
} }
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
View 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
View File

@@ -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;

633
sqlite.go

File diff suppressed because it is too large Load Diff

View File

@@ -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

File diff suppressed because it is too large Load Diff