mirror of
https://github.com/glebarez/go-sqlite.git
synced 2025-10-05 15:56:52 +08:00
Do not use fixed heap on Linux. Updates #12.
modified: all_test.go modified: generator.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
This commit is contained in:
36
all_test.go
36
all_test.go
@@ -312,3 +312,39 @@ func TestIssue11(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/cznic/sqlite/issues/12
|
||||||
|
func TestMemDB(t *testing.T) {
|
||||||
|
// Verify we can create out-of-the heap memory DB instance.
|
||||||
|
db, err := sql.Open(driverName, "file::memory:")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
db.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
v := strings.Repeat("a", 1024)
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
create table t(s string);
|
||||||
|
begin;
|
||||||
|
`); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := db.Prepare("insert into t values(?)")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Heap used to be fixed at 32MB.
|
||||||
|
for i := 0; i < (64<<20)/len(v); i++ {
|
||||||
|
if _, err := s.Exec(v); err != nil {
|
||||||
|
t.Fatalf("%v * %v= %v: %v", i, len(v), i*len(v), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := db.Exec(`commit;`); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
23
generator.go
23
generator.go
@@ -61,33 +61,16 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/cznic/crt"
|
"github.com/cznic/crt"
|
||||||
"github.com/edsrzf/mmap-go"
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const minAlloc = 2<<5
|
var inf = math.Inf(1)
|
||||||
|
|
||||||
var (
|
|
||||||
inf = math.Inf(1)
|
|
||||||
)
|
|
||||||
|
|
||||||
func ftrace(s string, args ...interface{}) {
|
func ftrace(s string, args ...interface{}) {
|
||||||
_, fn, fl, _ := runtime.Caller(1)
|
_, fn, fl, _ := runtime.Caller(1)
|
||||||
fmt.Fprintf(os.Stderr, "# %%s:%%d: %%v\n", path.Base(fn), fl, fmt.Sprintf(s, args...))
|
fmt.Fprintf(os.Stderr, "# %%s:%%d: %%v\n", path.Base(fn), fl, fmt.Sprintf(s, args...))
|
||||||
os.Stderr.Sync()
|
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)))
|
|
||||||
}
|
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -265,11 +248,13 @@ func main() {
|
|||||||
|
|
||||||
asta, src := build(
|
asta, src := build(
|
||||||
`
|
`
|
||||||
|
#define HAVE_MALLOC_H 1
|
||||||
|
#define HAVE_MALLOC_USABLE_SIZE 1
|
||||||
#define HAVE_USLEEP 1
|
#define HAVE_USLEEP 1
|
||||||
#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_USE_URI 1
|
#define SQLITE_USE_URI 1
|
||||||
|
#define SQLITE_WITHOUT_MSIZE 1
|
||||||
`,
|
`,
|
||||||
[][]string{
|
[][]string{
|
||||||
{"main.c"},
|
{"main.c"},
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
27
main.c
27
main.c
@@ -1,36 +1,13 @@
|
|||||||
// Copyright 2017 The Sqlite Authors. All rights reserved.
|
// Copyright 2017 The Sqlite Authors. All rights reserved.
|
||||||
// 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.
|
||||||
// SQLite Is Public Domain
|
|
||||||
|
|
||||||
// +build ignore
|
// +build ignore
|
||||||
|
|
||||||
#define minAlloc (2<<5)
|
|
||||||
|
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
init(-1);
|
// Prevent the linker from optimizing out everything.
|
||||||
}
|
int (*f) (int, ...) = sqlite3_config;
|
||||||
|
|
||||||
int init(int heapSize)
|
|
||||||
{
|
|
||||||
void *heap = malloc(heapSize);
|
|
||||||
if (heap == 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rc = sqlite3_config(SQLITE_CONFIG_HEAP, heap, heapSize, minAlloc);
|
|
||||||
if (rc) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = sqlite3_threadsafe();
|
|
||||||
if (!rc) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
36
sqlite.go
36
sqlite.go
@@ -34,15 +34,26 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
driverName = "sqlite"
|
driverName = "sqlite"
|
||||||
heapReserve = 1 << 20
|
ptrSize = 1 << (^uintptr(0)>>32&1 + ^uintptr(0)>>16&1 + ^uintptr(0)>>8&1 + 3) / 8
|
||||||
heapSize = 32 << 20
|
|
||||||
ptrSize = 1 << (^uintptr(0)>>32&1 + ^uintptr(0)>>16&1 + ^uintptr(0)>>8&1 + 3) / 8
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
if v := bin.Init(heapSize, heapReserve); v != 0 {
|
tls := crt.NewTLS()
|
||||||
panic(fmt.Errorf("initialization failed: %v", v))
|
crt.X__register_stdfiles(tls, bin.Xstdin, bin.Xstdout, bin.Xstderr)
|
||||||
|
if bin.Xsqlite3_threadsafe(tls) == 0 {
|
||||||
|
panic(fmt.Errorf("sqlite: thread safety configuration error"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if bin.Xsqlite3_config(
|
||||||
|
tls,
|
||||||
|
bin.XSQLITE_CONFIG_LOG,
|
||||||
|
func(tls *crt.TLS, pArg unsafe.Pointer, iErrCode int32, zMsg *int8) {
|
||||||
|
fmt.Fprintf(os.Stderr, "%v(%#x): %s\n", iErrCode, iErrCode, crt.GoString(zMsg))
|
||||||
|
},
|
||||||
|
unsafe.Pointer(nil),
|
||||||
|
) != 0 {
|
||||||
|
panic("sqlite: cannot configure error log callback")
|
||||||
}
|
}
|
||||||
|
|
||||||
sql.Register(driverName, newDrv())
|
sql.Register(driverName, newDrv())
|
||||||
@@ -58,12 +69,12 @@ func tracer(rx interface{}, format string, args ...interface{}) {
|
|||||||
|
|
||||||
type result struct {
|
type result struct {
|
||||||
*stmt
|
*stmt
|
||||||
lastInsertId int64
|
lastInsertID int64
|
||||||
rowsAffected int
|
rowsAffected int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *result) String() string {
|
func (r *result) String() string {
|
||||||
return fmt.Sprintf("&%T@%p{stmt: %p, LastInsertId: %v, RowsAffected: %v}", *r, r, r.stmt, r.lastInsertId, r.rowsAffected)
|
return fmt.Sprintf("&%T@%p{stmt: %p, LastInsertId: %v, RowsAffected: %v}", *r, r, r.stmt, r.lastInsertID, r.rowsAffected)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newResult(s *stmt) (_ *result, err error) {
|
func newResult(s *stmt) (_ *result, err error) {
|
||||||
@@ -72,7 +83,7 @@ func newResult(s *stmt) (_ *result, err error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.lastInsertId, err = r.lastInsertRowID(); err != nil {
|
if r.lastInsertID, err = r.lastInsertRowID(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +108,7 @@ func (r *result) LastInsertId() (int64, error) {
|
|||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.lastInsertId, nil
|
return r.lastInsertID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RowsAffected returns the number of rows affected by the query.
|
// RowsAffected returns the number of rows affected by the query.
|
||||||
@@ -693,8 +704,8 @@ func (s *stmt) step(pstmt unsafe.Pointer) (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 *int8) error {
|
func (s *stmt) prepareV2(zSQL *int8) error {
|
||||||
if rc := bin.Xsqlite3_prepare_v2(s.tls, s.pdb(), zSql, -1, s.ppstmt, s.pzTail); rc != bin.XSQLITE_OK {
|
if rc := bin.Xsqlite3_prepare_v2(s.tls, s.pdb(), zSQL, -1, s.ppstmt, s.pzTail); rc != bin.XSQLITE_OK {
|
||||||
return s.errstr(rc)
|
return s.errstr(rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1050,6 +1061,7 @@ func (c *conn) close() (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Driver implements database/sql/driver.Driver.
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
@@ -63,11 +63,7 @@ func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driv
|
|||||||
func toNamedValues2(vals []driver.NamedValue) []namedValue {
|
func toNamedValues2(vals []driver.NamedValue) []namedValue {
|
||||||
args := make([]namedValue, 0, len(vals))
|
args := make([]namedValue, 0, len(vals))
|
||||||
for _, val := range vals {
|
for _, val := range vals {
|
||||||
args = append(args, namedValue{
|
args = append(args, namedValue(val))
|
||||||
Name: val.Name,
|
|
||||||
Ordinal: val.Ordinal,
|
|
||||||
Value: val.Value,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user