├── sqlite.h ├── generate.go ├── README.md ├── main.c ├── trace_enabled.go ├── trace_disabled.go ├── CONTRIBUTORS ├── AUTHORS ├── sqlite_go18_test.go ├── testdata └── mptest │ ├── config01.test │ ├── crash02.subtest │ ├── config02.test │ ├── crash01.test │ └── multiwrite01.test ├── doc.go ├── LICENSE ├── SQLITE-LICENSE ├── Makefile ├── sqlite_go18.go ├── internal ├── threadtest2 │ ├── threadtest2_linux_386.go │ └── threadtest2_linux_amd64.go ├── sqlite.org │ └── sqlite-src-3190300 │ │ └── test │ │ ├── threadtest1.c │ │ └── threadtest4.c ├── threadtest1 │ ├── threadtest1_linux_386.go │ └── threadtest1_linux_amd64.go └── threadtest4 │ ├── threadtest4_linux_386.go │ └── threadtest4_linux_amd64.go ├── z_linux_test.go ├── all_test.go ├── generator.go └── sqlite.go /sqlite.h: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | // Help some old tests work. 4 | 5 | #include "sqlite3.h" 6 | #include 7 | 8 | #define sqlite sqlite3 9 | -------------------------------------------------------------------------------- /generate.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Sqlite Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:generate go run generator.go 6 | 7 | package sqlite 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `github.com/cznic/sqlite` has moved to [`modernc.org/sqlite`](https://godoc.org/modernc.org/sqlite) ([vcs](https://gitlab.com/cznic/sqlite)). 2 | 3 | Please update your import paths to `modernc.org/sqlite`. 4 | 5 | This repo is now archived. 6 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Sqlite Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build ignore 6 | 7 | int main(int argc, char **argv) 8 | { 9 | } 10 | -------------------------------------------------------------------------------- /trace_enabled.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Virtual Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build sqlite.trace 6 | 7 | package sqlite 8 | 9 | const trace = true 10 | -------------------------------------------------------------------------------- /trace_disabled.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Virtual Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !sqlite.trace 6 | 7 | package sqlite 8 | 9 | const trace = false 10 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This file lists people who contributed code to this repository. The AUTHORS 2 | # file lists the copyright holders; this file lists people. 3 | # 4 | # Names should be added to this file like so: 5 | # Name 6 | # 7 | # Please keep the list sorted. 8 | 9 | Alexander Menzhinsky 10 | Jan Mercl <0xjnml@gmail.com> 11 | Steffen Butzer 12 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This file lists authors for copyright purposes. This file is distinct from 2 | # the CONTRIBUTORS files. See the latter for an explanation. 3 | # 4 | # Names should be added to this file as: 5 | # Name or Organization 6 | # 7 | # The email address is not required for organizations. 8 | # 9 | # Please keep the list sorted. 10 | 11 | Jan Mercl <0xjnml@gmail.com> 12 | Steffen Butzer 13 | -------------------------------------------------------------------------------- /sqlite_go18_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Sqlite Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //+build go1.8 6 | 7 | package sqlite 8 | 9 | import ( 10 | "database/sql" 11 | "os" 12 | "reflect" 13 | "testing" 14 | ) 15 | 16 | func TestNamedParameters(t *testing.T) { 17 | dir, db := tempDB(t) 18 | defer func() { 19 | db.Close() 20 | os.RemoveAll(dir) 21 | }() 22 | 23 | _, err := db.Exec(` 24 | create table t(s1 varchar(32), s2 varchar(32), s3 varchar(32), s4 varchar(32)); 25 | insert into t values(?, @aa, $aa, @bb); 26 | `, "1", sql.Named("aa", "one"), sql.Named("bb", "two")) 27 | 28 | if err != nil { 29 | t.Fatal(err) 30 | } 31 | 32 | rows, err := db.Query("select * from t") 33 | if err != nil { 34 | t.Fatal(err) 35 | } 36 | 37 | rec := make([]string, 4) 38 | for rows.Next() { 39 | if err := rows.Scan(&rec[0], &rec[1], &rec[2], &rec[3]); err != nil { 40 | t.Fatal(err) 41 | } 42 | } 43 | 44 | w := []string{"1", "one", "one", "two"} 45 | if !reflect.DeepEqual(rec, w) { 46 | t.Fatal(rec, w) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /testdata/mptest/config01.test: -------------------------------------------------------------------------------- 1 | /* 2 | ** Configure five tasks in different ways, then run tests. 3 | */ 4 | --if vfsname() GLOB 'unix' 5 | PRAGMA page_size=8192; 6 | --task 1 7 | PRAGMA journal_mode=PERSIST; 8 | PRAGMA mmap_size=0; 9 | --end 10 | --task 2 11 | PRAGMA journal_mode=TRUNCATE; 12 | PRAGMA mmap_size=28672; 13 | --end 14 | --task 3 15 | PRAGMA journal_mode=MEMORY; 16 | --end 17 | --task 4 18 | PRAGMA journal_mode=OFF; 19 | --end 20 | --task 4 21 | PRAGMA mmap_size(268435456); 22 | --end 23 | --source multiwrite01.test 24 | --wait all 25 | PRAGMA page_size=16384; 26 | VACUUM; 27 | CREATE TABLE pgsz(taskid, sz INTEGER); 28 | --task 1 29 | INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size')); 30 | --end 31 | --task 2 32 | INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size')); 33 | --end 34 | --task 3 35 | INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size')); 36 | --end 37 | --task 4 38 | INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size')); 39 | --end 40 | --task 5 41 | INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size')); 42 | --end 43 | --source multiwrite01.test 44 | --wait all 45 | SELECT sz FROM pgsz; 46 | --match 16384 16384 16384 16384 16384 47 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Sqlite Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package sqlite is an in-process implementation of a self-contained, 6 | // serverless, zero-configuration, transactional SQL database engine. (Work In Progress) 7 | // 8 | // Changelog 9 | // 10 | // 2017-06-10 Windows/Intel no more uses the VM (thanks Steffen Butzer). 11 | // 12 | // 2017-06-05 Linux/Intel no more uses the VM (cznic/virtual). 13 | // 14 | // Connecting to a database 15 | // 16 | // To access a Sqlite database do something like 17 | // 18 | // import ( 19 | // "database/sql" 20 | // 21 | // _ "github.com/cznic/sqlite" 22 | // ) 23 | // 24 | // ... 25 | // 26 | // 27 | // db, err := sql.Open("sqlite", dsnURI) 28 | // 29 | // ... 30 | // 31 | // 32 | // Do not use in production 33 | // 34 | // This is an experimental, pre-alpha, technology preview package. 35 | // 36 | // The alpha release is due when the C runtime support of SQLite in cznic/crt 37 | // will be complete. 38 | // 39 | // Supported platforms and architectures 40 | // 41 | // See http://github.com/cznic/ccir. To add a newly supported os/arch 42 | // combination to this package try running 'go generate'. 43 | // 44 | // Sqlite documentation 45 | // 46 | // See https://sqlite.org/docs.html 47 | package sqlite 48 | -------------------------------------------------------------------------------- /testdata/mptest/crash02.subtest: -------------------------------------------------------------------------------- 1 | /* 2 | ** This script is called from crash01.test and config02.test and perhaps other 3 | ** script. After the database file has been set up, make a big rollback 4 | ** journal in client 1, then crash client 1. 5 | ** Then in the other clients, do an integrity check. 6 | */ 7 | --task 1 leave-hot-journal 8 | --sleep 5 9 | --finish 10 | PRAGMA cache_size=10; 11 | BEGIN; 12 | UPDATE t1 SET b=randomblob(20000); 13 | UPDATE t2 SET b=randomblob(20000); 14 | UPDATE t3 SET b=randomblob(20000); 15 | UPDATE t4 SET b=randomblob(20000); 16 | UPDATE t5 SET b=randomblob(20000); 17 | UPDATE t1 SET b=NULL; 18 | UPDATE t2 SET b=NULL; 19 | UPDATE t3 SET b=NULL; 20 | UPDATE t4 SET b=NULL; 21 | UPDATE t5 SET b=NULL; 22 | --print Task one crashing an incomplete transaction 23 | --exit 1 24 | --end 25 | --task 2 integrity_check-2 26 | SELECT count(*) FROM t1; 27 | --match 64 28 | --sleep 100 29 | PRAGMA integrity_check(10); 30 | --match ok 31 | --end 32 | --task 3 integrity_check-3 33 | SELECT count(*) FROM t1; 34 | --match 64 35 | --sleep 100 36 | PRAGMA integrity_check(10); 37 | --match ok 38 | --end 39 | --task 4 integrity_check-4 40 | SELECT count(*) FROM t1; 41 | --match 64 42 | --sleep 100 43 | PRAGMA integrity_check(10); 44 | --match ok 45 | --end 46 | --task 5 integrity_check-5 47 | SELECT count(*) FROM t1; 48 | --match 64 49 | --sleep 100 50 | PRAGMA integrity_check(10); 51 | --match ok 52 | --end 53 | --wait all 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 The Sqlite Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the names of the authors nor the names of the 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /SQLITE-LICENSE: -------------------------------------------------------------------------------- 1 | SQLite Is Public Domain 2 | 3 | All of the code and documentation in SQLite has been dedicated to the public 4 | domain by the authors. All code authors, and representatives of the companies 5 | they work for, have signed affidavits dedicating their contributions to the 6 | public domain and originals of those signed affidavits are stored in a firesafe 7 | at the main offices of Hwaci. Anyone is free to copy, modify, publish, use, 8 | compile, sell, or distribute the original SQLite code, either in source code 9 | form or as a compiled binary, for any purpose, commercial or non-commercial, 10 | and by any means. 11 | 12 | The previous paragraph applies to the deliverable code and documentation in 13 | SQLite - those parts of the SQLite library that you actually bundle and ship 14 | with a larger application. Some scripts used as part of the build process (for 15 | example the "configure" scripts generated by autoconf) might fall under other 16 | open-source licenses. Nothing from these build scripts ever reaches the final 17 | deliverable SQLite library, however, and so the licenses associated with those 18 | scripts should not be a factor in assessing your rights to copy and use the 19 | SQLite library. 20 | 21 | All of the deliverable code in SQLite has been written from scratch. No code 22 | has been taken from other projects or from the open internet. Every line of 23 | code can be traced back to its original author, and all of those authors have 24 | public domain dedications on file. So the SQLite code base is clean and is 25 | uncontaminated with licensed code from other projects. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2017 The Sqlite Authors. All rights reserved. 2 | # Use of this source code is governed by a BSD-style 3 | # license that can be found in the LICENSE file. 4 | 5 | .PHONY: all clean cover cpu editor internalError later mem nuke todo edit 6 | 7 | grep=--include=*.go --include=*.l --include=*.y --include=*.yy 8 | ngrep='TODOOK\|parser\.go\|scanner\.go\|.*_string\.go' 9 | 10 | all: editor 11 | go test 2>&1 | tee log 12 | go vet 2>&1 | grep -v $(ngrep) || true 13 | golint 2>&1 | grep -v $(ngrep) || true 14 | make todo 15 | unused . || true 16 | misspell *.go 17 | gosimple || true 18 | maligned || true 19 | unconvert -apply 20 | 21 | clean: 22 | go clean 23 | rm -f *~ *.test *.out test.db* tt4-test*.db* test_sv.* testdb-* 24 | 25 | cover: 26 | t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t 27 | 28 | cpu: clean 29 | go test -run @ -bench . -cpuprofile cpu.out 30 | go tool pprof -lines *.test cpu.out 31 | 32 | edit: 33 | @ 1>/dev/null 2>/dev/null gvim -p Makefile main.c *.go 34 | 35 | editor: 36 | gofmt -l -s -w *.go 37 | indent -linux *.c 38 | go test -i 39 | 40 | internalError: 41 | egrep -ho '"internal error.*"' *.go | sort | cat -n 42 | 43 | later: 44 | @grep -n $(grep) LATER * || true 45 | @grep -n $(grep) MAYBE * || true 46 | 47 | mem: clean 48 | go test -run @ -bench . -memprofile mem.out -memprofilerate 1 -timeout 24h 49 | go tool pprof -lines -web -alloc_space *.test mem.out 50 | 51 | nuke: clean 52 | go clean -i 53 | 54 | todo: 55 | @grep -nr $(grep) ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* * | grep -v $(ngrep) || true 56 | @grep -nr $(grep) TODO * | grep -v $(ngrep) || true 57 | @grep -nr $(grep) BUG * | grep -v $(ngrep) || true 58 | @grep -nr $(grep) [^[:alpha:]]println * | grep -v $(ngrep) || true 59 | -------------------------------------------------------------------------------- /sqlite_go18.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Sqlite Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //+build go1.8 6 | 7 | package sqlite 8 | 9 | import ( 10 | "context" 11 | "database/sql/driver" 12 | "errors" 13 | "unsafe" 14 | ) 15 | 16 | // Ping implements driver.Pinger 17 | func (c *conn) Ping(ctx context.Context) error { 18 | c.Lock() 19 | defer c.Unlock() 20 | 21 | if uintptr(unsafe.Pointer(c.ppdb)) == 0 { 22 | return errors.New("db is closed") 23 | } 24 | 25 | _, err := c.ExecContext(ctx, "select 1", nil) 26 | return err 27 | } 28 | 29 | // BeginTx implements driver.ConnBeginTx 30 | func (c *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { 31 | return c.begin(ctx, txOptions{ 32 | Isolation: int(opts.Isolation), 33 | ReadOnly: opts.ReadOnly, 34 | }) 35 | } 36 | 37 | // PrepareContext implements driver.ConnPrepareContext 38 | func (c *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { 39 | return c.prepare(ctx, query) 40 | } 41 | 42 | // ExecContext implements driver.ExecerContext 43 | func (c *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { 44 | return c.exec(ctx, query, toNamedValues2(args)) 45 | } 46 | 47 | // QueryContext implements driver.QueryerContext 48 | func (c *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { 49 | return c.query(ctx, query, toNamedValues2(args)) 50 | } 51 | 52 | // ExecContext implements driver.StmtExecContext 53 | func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { 54 | return s.exec(ctx, toNamedValues2(args)) 55 | } 56 | 57 | // QueryContext implements driver.StmtQueryContext 58 | func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { 59 | return s.query(ctx, toNamedValues2(args)) 60 | } 61 | 62 | // converts []driver.NamedValue to []namedValue 63 | func toNamedValues2(vals []driver.NamedValue) []namedValue { 64 | args := make([]namedValue, 0, len(vals)) 65 | for _, val := range vals { 66 | args = append(args, namedValue(val)) 67 | } 68 | return args 69 | } 70 | -------------------------------------------------------------------------------- /testdata/mptest/config02.test: -------------------------------------------------------------------------------- 1 | /* 2 | ** Configure five tasks in different ways, then run tests. 3 | */ 4 | PRAGMA page_size=512; 5 | --task 1 6 | PRAGMA mmap_size=0; 7 | --end 8 | --task 2 9 | PRAGMA mmap_size=28672; 10 | --end 11 | --task 3 12 | PRAGMA mmap_size=8192; 13 | --end 14 | --task 4 15 | PRAGMA mmap_size=65536; 16 | --end 17 | --task 5 18 | PRAGMA mmap_size=268435456; 19 | --end 20 | --source multiwrite01.test 21 | --source crash02.subtest 22 | PRAGMA page_size=1024; 23 | VACUUM; 24 | CREATE TABLE pgsz(taskid, sz INTEGER); 25 | --task 1 26 | INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size')); 27 | --end 28 | --task 2 29 | INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size')); 30 | --end 31 | --task 3 32 | INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size')); 33 | --end 34 | --task 4 35 | INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size')); 36 | --end 37 | --task 5 38 | INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size')); 39 | --end 40 | --source multiwrite01.test 41 | --source crash02.subtest 42 | --wait all 43 | SELECT sz FROM pgsz; 44 | --match 1024 1024 1024 1024 1024 45 | PRAGMA page_size=2048; 46 | VACUUM; 47 | DELETE FROM pgsz; 48 | --task 1 49 | INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size')); 50 | --end 51 | --task 2 52 | INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size')); 53 | --end 54 | --task 3 55 | INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size')); 56 | --end 57 | --task 4 58 | INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size')); 59 | --end 60 | --task 5 61 | INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size')); 62 | --end 63 | --source multiwrite01.test 64 | --source crash02.subtest 65 | --wait all 66 | SELECT sz FROM pgsz; 67 | --match 2048 2048 2048 2048 2048 68 | PRAGMA page_size=8192; 69 | VACUUM; 70 | DELETE FROM pgsz; 71 | --task 1 72 | INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size')); 73 | --end 74 | --task 2 75 | INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size')); 76 | --end 77 | --task 3 78 | INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size')); 79 | --end 80 | --task 4 81 | INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size')); 82 | --end 83 | --task 5 84 | INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size')); 85 | --end 86 | --source multiwrite01.test 87 | --source crash02.subtest 88 | --wait all 89 | SELECT sz FROM pgsz; 90 | --match 8192 8192 8192 8192 8192 91 | PRAGMA page_size=16384; 92 | VACUUM; 93 | DELETE FROM pgsz; 94 | --task 1 95 | INSERT INTO pgsz VALUES(1, eval('PRAGMA page_size')); 96 | --end 97 | --task 2 98 | INSERT INTO pgsz VALUES(2, eval('PRAGMA page_size')); 99 | --end 100 | --task 3 101 | INSERT INTO pgsz VALUES(3, eval('PRAGMA page_size')); 102 | --end 103 | --task 4 104 | INSERT INTO pgsz VALUES(4, eval('PRAGMA page_size')); 105 | --end 106 | --task 5 107 | INSERT INTO pgsz VALUES(5, eval('PRAGMA page_size')); 108 | --end 109 | --source multiwrite01.test 110 | --source crash02.subtest 111 | --wait all 112 | SELECT sz FROM pgsz; 113 | --match 16384 16384 16384 16384 16384 114 | PRAGMA auto_vacuum=FULL; 115 | VACUUM; 116 | --source multiwrite01.test 117 | --source crash02.subtest 118 | --wait all 119 | PRAGMA auto_vacuum=FULL; 120 | PRAGMA page_size=512; 121 | VACUUM; 122 | --source multiwrite01.test 123 | --source crash02.subtest 124 | -------------------------------------------------------------------------------- /testdata/mptest/crash01.test: -------------------------------------------------------------------------------- 1 | /* Test cases involving incomplete transactions that must be rolled back. 2 | */ 3 | --task 1 4 | DROP TABLE IF EXISTS t1; 5 | CREATE TABLE t1(a INTEGER PRIMARY KEY, b); 6 | --sleep 1 7 | INSERT INTO t1 VALUES(1, randomblob(2000)); 8 | INSERT INTO t1 VALUES(2, randomblob(1000)); 9 | --sleep 1 10 | INSERT INTO t1 SELECT a+2, randomblob(1500) FROM t1; 11 | INSERT INTO t1 SELECT a+4, randomblob(1500) FROM t1; 12 | INSERT INTO t1 SELECT a+8, randomblob(1500) FROM t1; 13 | --sleep 1 14 | INSERT INTO t1 SELECT a+16, randomblob(1500) FROM t1; 15 | --sleep 1 16 | INSERT INTO t1 SELECT a+32, randomblob(1500) FROM t1; 17 | SELECT count(*) FROM t1; 18 | --match 64 19 | SELECT avg(length(b)) FROM t1; 20 | --match 1500.0 21 | --sleep 2 22 | UPDATE t1 SET b='x'||a||'y'; 23 | SELECT sum(length(b)) FROM t1; 24 | --match 247 25 | SELECT a FROM t1 WHERE b='x17y'; 26 | --match 17 27 | CREATE INDEX t1b ON t1(b); 28 | SELECT a FROM t1 WHERE b='x17y'; 29 | --match 17 30 | SELECT a FROM t1 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; 31 | --match 29 28 27 26 25 32 | --end 33 | --wait 1 34 | --task 2 35 | DROP TABLE IF EXISTS t2; 36 | CREATE TABLE t2(a INTEGER PRIMARY KEY, b); 37 | INSERT INTO t2 SELECT a, b FROM t1; 38 | UPDATE t1 SET b='x'||a||'y'; 39 | SELECT sum(length(b)) FROM t2; 40 | --match 247 41 | SELECT a FROM t2 WHERE b='x17y'; 42 | --match 17 43 | CREATE INDEX t2b ON t2(b); 44 | SELECT a FROM t2 WHERE b='x17y'; 45 | --match 17 46 | SELECT a FROM t2 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; 47 | --match 29 28 27 26 25 48 | --end 49 | --task 3 50 | DROP TABLE IF EXISTS t3; 51 | CREATE TABLE t3(a INTEGER PRIMARY KEY, b); 52 | INSERT INTO t3 SELECT a, b FROM t1; 53 | UPDATE t1 SET b='x'||a||'y'; 54 | SELECT sum(length(b)) FROM t3; 55 | --match 247 56 | SELECT a FROM t3 WHERE b='x17y'; 57 | --match 17 58 | CREATE INDEX t3b ON t3(b); 59 | SELECT a FROM t3 WHERE b='x17y'; 60 | --match 17 61 | SELECT a FROM t3 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; 62 | --match 29 28 27 26 25 63 | --end 64 | --task 4 65 | DROP TABLE IF EXISTS t4; 66 | CREATE TABLE t4(a INTEGER PRIMARY KEY, b); 67 | INSERT INTO t4 SELECT a, b FROM t1; 68 | UPDATE t1 SET b='x'||a||'y'; 69 | SELECT sum(length(b)) FROM t4; 70 | --match 247 71 | SELECT a FROM t4 WHERE b='x17y'; 72 | --match 17 73 | CREATE INDEX t4b ON t4(b); 74 | SELECT a FROM t4 WHERE b='x17y'; 75 | --match 17 76 | SELECT a FROM t4 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; 77 | --match 29 28 27 26 25 78 | --end 79 | --task 5 80 | DROP TABLE IF EXISTS t5; 81 | CREATE TABLE t5(a INTEGER PRIMARY KEY, b); 82 | INSERT INTO t5 SELECT a, b FROM t1; 83 | UPDATE t1 SET b='x'||a||'y'; 84 | SELECT sum(length(b)) FROM t5; 85 | --match 247 86 | SELECT a FROM t5 WHERE b='x17y'; 87 | --match 17 88 | CREATE INDEX t5b ON t5(b); 89 | SELECT a FROM t5 WHERE b='x17y'; 90 | --match 17 91 | SELECT a FROM t5 WHERE b GLOB 'x2?y' ORDER BY b DESC LIMIT 5; 92 | --match 29 28 27 26 25 93 | --end 94 | 95 | --wait all 96 | /* After the database file has been set up, run the crash2 subscript 97 | ** multiple times. */ 98 | --source crash02.subtest 99 | --source crash02.subtest 100 | --source crash02.subtest 101 | --source crash02.subtest 102 | --source crash02.subtest 103 | --source crash02.subtest 104 | --source crash02.subtest 105 | --source crash02.subtest 106 | --source crash02.subtest 107 | -------------------------------------------------------------------------------- /internal/threadtest2/threadtest2_linux_386.go: -------------------------------------------------------------------------------- 1 | // Code generated by ccgo. DO NOT EDIT. 2 | 3 | // threadtest2 4 | // /* 5 | // ** 2004 January 13 6 | // ** 7 | // ** The author disclaims copyright to this source code. In place of 8 | // ** a legal notice, here is a blessing: 9 | // ** 10 | // ** May you do good and not evil. 11 | // ** May you find forgiveness for yourself and forgive others. 12 | // ** May you share freely, never taking more than you give. 13 | // ** 14 | // ************************************************************************* 15 | // ** This file implements a simple standalone program used to test whether 16 | // ** or not the SQLite library is threadsafe. 17 | // ** 18 | // ** This file is NOT part of the standard SQLite library. It is used for 19 | // ** testing only. 20 | // */ 21 | package main 22 | 23 | import ( 24 | "math" 25 | "os" 26 | "unsafe" 27 | 28 | "github.com/cznic/ccgo/crt" 29 | "github.com/cznic/sqlite/internal/bin" 30 | ) 31 | 32 | var argv []*int8 33 | 34 | func main() { 35 | for _, v := range os.Args { 36 | argv = append(argv, (*int8)(crt.CString(v))) 37 | } 38 | argv = append(argv, nil) 39 | X_start(crt.NewTLS(), int32(len(os.Args)), &argv[0]) 40 | } 41 | 42 | func X_start(tls *crt.TLS, _argc int32, _argv **int8) { 43 | crt.X__register_stdfiles(tls, Xstdin, Xstdout, Xstderr) 44 | crt.X__builtin_exit(tls, Xmain(tls, _argc, _argv)) 45 | } 46 | 47 | var Xstdin unsafe.Pointer 48 | 49 | func init() { 50 | Xstdin = unsafe.Pointer(&X__stdfiles) 51 | } 52 | 53 | var X__stdfiles [3]unsafe.Pointer 54 | 55 | var Xstdout unsafe.Pointer 56 | 57 | func init() { 58 | Xstdout = unsafe.Pointer(uintptr(unsafe.Pointer(&X__stdfiles)) + 4) 59 | } 60 | 61 | var Xstderr unsafe.Pointer 62 | 63 | func init() { 64 | Xstderr = unsafe.Pointer(uintptr(unsafe.Pointer(&X__stdfiles)) + 8) 65 | } 66 | 67 | // C comment 68 | // /* 69 | // ** Initialize the database and start the threads 70 | // */ 71 | func Xmain(tls *crt.TLS, _argc int32, _argv **int8) (r0 int32) { 72 | var _i, _rc int32 73 | var _1_zJournal *int8 74 | var _db unsafe.Pointer 75 | var _aThread [5]uint32 76 | r0 = int32(0) 77 | if crt.Xstrcmp(tls, str(0), str(8)) != 0 { 78 | _1_zJournal = bin.Xsqlite3_mprintf(tls, str(17), unsafe.Pointer(str(0))) 79 | crt.Xunlink(tls, str(0)) 80 | crt.Xunlink(tls, _1_zJournal) 81 | bin.Xsqlite3_free(tls, unsafe.Pointer(_1_zJournal)) 82 | } 83 | bin.Xsqlite3_open(tls, str(0), (**bin.Xsqlite3)(unsafe.Pointer(&_db))) 84 | if _db == nil { 85 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(28)) 86 | crt.Xexit(tls, int32(1)) 87 | } 88 | _rc = bin.Xsqlite3_exec(tls, (*bin.Xsqlite3)(_db), str(59), nil, nil, nil) 89 | if _rc != 0 { 90 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(79), _rc) 91 | crt.Xexit(tls, int32(1)) 92 | } 93 | bin.Xsqlite3_close(tls, (*bin.Xsqlite3)(_db)) 94 | _i = int32(0) 95 | _3: 96 | if uint32(_i) >= uint32(5) { 97 | goto _6 98 | } 99 | crt.Xpthread_create(tls, elem0((*uint32)(unsafe.Pointer(&_aThread)), uintptr(_i)), nil, Xworker, crt.U2P(uintptr(_i))) 100 | _i += 1 101 | goto _3 102 | _6: 103 | _i = int32(0) 104 | _7: 105 | if uint32(_i) >= uint32(5) { 106 | goto _10 107 | } 108 | crt.Xpthread_join(tls, *elem0((*uint32)(unsafe.Pointer(&_aThread)), uintptr(_i)), nil) 109 | _i += 1 110 | goto _7 111 | _10: 112 | if Xall_stop == 0 { 113 | crt.Xprintf(tls, str(107)) 114 | return int32(0) 115 | } 116 | crt.Xprintf(tls, str(129)) 117 | return int32(1) 118 | 119 | _ = _aThread 120 | panic(0) 121 | } 122 | 123 | // C comment 124 | // /* 125 | // ** This is the worker thread 126 | // */ 127 | func Xworker(tls *crt.TLS, _workerArg unsafe.Pointer) (r0 unsafe.Pointer) { 128 | var _id, _rc, _cnt int32 129 | var _db unsafe.Pointer 130 | _id = int32(crt.P2U(_workerArg)) 131 | _cnt = int32(0) 132 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(147), _id) 133 | _0: 134 | if Xall_stop != 0 || postInc1(&_cnt, 1) >= int32(10000) { 135 | goto _1 136 | } 137 | if (_cnt % int32(100)) == int32(0) { 138 | crt.Xprintf(tls, str(167), _id, _cnt) 139 | } 140 | _3: 141 | if bin.Xsqlite3_open(tls, str(0), (**bin.Xsqlite3)(unsafe.Pointer(&_db))) != int32(0) { 142 | crt.Xsched_yield(tls) 143 | goto _3 144 | } 145 | bin.Xsqlite3_exec(tls, (*bin.Xsqlite3)(_db), str(175), nil, nil, nil) 146 | if Xall_stop != 0 { 147 | bin.Xsqlite3_close(tls, (*bin.Xsqlite3)(_db)) 148 | goto _1 149 | } 150 | _rc = bin.Xsqlite3_exec(tls, (*bin.Xsqlite3)(_db), str(198), nil, nil, nil) 151 | bin.Xsqlite3_close(tls, (*bin.Xsqlite3)(_db)) 152 | goto _0 153 | _1: 154 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(234), _id) 155 | return nil 156 | 157 | _ = _rc 158 | panic(0) 159 | } 160 | 161 | // C comment 162 | // /* 163 | // ** When this variable becomes non-zero, all threads stop 164 | // ** what they are doing. 165 | // */ 166 | var Xall_stop int32 167 | 168 | func bool2int(b bool) int32 { 169 | if b { 170 | return 1 171 | } 172 | return 0 173 | } 174 | func bug20530(interface{}) {} //TODO remove when https://github.com/golang/go/issues/20530 is fixed. 175 | func init() { nzf32 *= -1; nzf64 *= -1 } 176 | 177 | var inf = math.Inf(1) 178 | var nzf32 float32 // -0.0 179 | var nzf64 float64 // -0.0 180 | func elem0(a *uint32, index uintptr) *uint32 { 181 | return (*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 4*index)) 182 | } 183 | func postInc1(p *int32, d int32) int32 { v := *p; *p += d; return v } 184 | func str(n int) *int8 { return (*int8)(unsafe.Pointer(&strTab[n])) } 185 | func wstr(n int) *int32 { return (*int32)(unsafe.Pointer(&strTab[n])) } 186 | 187 | var strTab = []byte("test.db\x00:memory:\x00%s-journal\x00unable to initialize database\x0a\x00CREATE TABLE t1(x);\x00cannot create table t1: %d\x0a\x00Everything seems ok.\x0a\x00We hit an error.\x0a\x00Starting worker %d\x0a\x00%d: %d\x0a\x00PRAGMA synchronous=OFF\x00INSERT INTO t1 VALUES('bogus data')\x00Worker %d finished\x0a\x00") 188 | -------------------------------------------------------------------------------- /internal/threadtest2/threadtest2_linux_amd64.go: -------------------------------------------------------------------------------- 1 | // Code generated by ccgo. DO NOT EDIT. 2 | 3 | // threadtest2 4 | // /* 5 | // ** 2004 January 13 6 | // ** 7 | // ** The author disclaims copyright to this source code. In place of 8 | // ** a legal notice, here is a blessing: 9 | // ** 10 | // ** May you do good and not evil. 11 | // ** May you find forgiveness for yourself and forgive others. 12 | // ** May you share freely, never taking more than you give. 13 | // ** 14 | // ************************************************************************* 15 | // ** This file implements a simple standalone program used to test whether 16 | // ** or not the SQLite library is threadsafe. 17 | // ** 18 | // ** This file is NOT part of the standard SQLite library. It is used for 19 | // ** testing only. 20 | // */ 21 | package main 22 | 23 | import ( 24 | "math" 25 | "os" 26 | "unsafe" 27 | 28 | "github.com/cznic/ccgo/crt" 29 | "github.com/cznic/sqlite/internal/bin" 30 | ) 31 | 32 | var argv []*int8 33 | 34 | func main() { 35 | for _, v := range os.Args { 36 | argv = append(argv, (*int8)(crt.CString(v))) 37 | } 38 | argv = append(argv, nil) 39 | X_start(crt.NewTLS(), int32(len(os.Args)), &argv[0]) 40 | } 41 | 42 | func X_start(tls *crt.TLS, _argc int32, _argv **int8) { 43 | crt.X__register_stdfiles(tls, Xstdin, Xstdout, Xstderr) 44 | crt.X__builtin_exit(tls, Xmain(tls, _argc, _argv)) 45 | } 46 | 47 | var Xstdin unsafe.Pointer 48 | 49 | func init() { 50 | Xstdin = unsafe.Pointer(&X__stdfiles) 51 | } 52 | 53 | var X__stdfiles [3]unsafe.Pointer 54 | 55 | var Xstdout unsafe.Pointer 56 | 57 | func init() { 58 | Xstdout = unsafe.Pointer(uintptr(unsafe.Pointer(&X__stdfiles)) + 8) 59 | } 60 | 61 | var Xstderr unsafe.Pointer 62 | 63 | func init() { 64 | Xstderr = unsafe.Pointer(uintptr(unsafe.Pointer(&X__stdfiles)) + 16) 65 | } 66 | 67 | // C comment 68 | // /* 69 | // ** Initialize the database and start the threads 70 | // */ 71 | func Xmain(tls *crt.TLS, _argc int32, _argv **int8) (r0 int32) { 72 | var _i, _rc int32 73 | var _1_zJournal *int8 74 | var _db unsafe.Pointer 75 | var _aThread [5]uint64 76 | r0 = int32(0) 77 | if crt.Xstrcmp(tls, str(0), str(8)) != 0 { 78 | _1_zJournal = bin.Xsqlite3_mprintf(tls, str(17), unsafe.Pointer(str(0))) 79 | crt.Xunlink(tls, str(0)) 80 | crt.Xunlink(tls, _1_zJournal) 81 | bin.Xsqlite3_free(tls, unsafe.Pointer(_1_zJournal)) 82 | } 83 | bin.Xsqlite3_open(tls, str(0), (**bin.Xsqlite3)(unsafe.Pointer(&_db))) 84 | if _db == nil { 85 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(28)) 86 | crt.Xexit(tls, int32(1)) 87 | } 88 | _rc = bin.Xsqlite3_exec(tls, (*bin.Xsqlite3)(_db), str(59), nil, nil, nil) 89 | if _rc != 0 { 90 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(79), _rc) 91 | crt.Xexit(tls, int32(1)) 92 | } 93 | bin.Xsqlite3_close(tls, (*bin.Xsqlite3)(_db)) 94 | _i = int32(0) 95 | _3: 96 | if uint64(_i) >= uint64(5) { 97 | goto _6 98 | } 99 | crt.Xpthread_create(tls, elem0((*uint64)(unsafe.Pointer(&_aThread)), uintptr(_i)), nil, Xworker, crt.U2P(uintptr(_i))) 100 | _i += 1 101 | goto _3 102 | _6: 103 | _i = int32(0) 104 | _7: 105 | if uint64(_i) >= uint64(5) { 106 | goto _10 107 | } 108 | crt.Xpthread_join(tls, *elem0((*uint64)(unsafe.Pointer(&_aThread)), uintptr(_i)), nil) 109 | _i += 1 110 | goto _7 111 | _10: 112 | if Xall_stop == 0 { 113 | crt.Xprintf(tls, str(107)) 114 | return int32(0) 115 | } 116 | crt.Xprintf(tls, str(129)) 117 | return int32(1) 118 | 119 | _ = _aThread 120 | panic(0) 121 | } 122 | 123 | // C comment 124 | // /* 125 | // ** This is the worker thread 126 | // */ 127 | func Xworker(tls *crt.TLS, _workerArg unsafe.Pointer) (r0 unsafe.Pointer) { 128 | var _id, _rc, _cnt int32 129 | var _db unsafe.Pointer 130 | _id = int32(crt.P2U(_workerArg)) 131 | _cnt = int32(0) 132 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(147), _id) 133 | _0: 134 | if Xall_stop != 0 || postInc1(&_cnt, 1) >= int32(10000) { 135 | goto _1 136 | } 137 | if (_cnt % int32(100)) == int32(0) { 138 | crt.Xprintf(tls, str(167), _id, _cnt) 139 | } 140 | _3: 141 | if bin.Xsqlite3_open(tls, str(0), (**bin.Xsqlite3)(unsafe.Pointer(&_db))) != int32(0) { 142 | crt.Xsched_yield(tls) 143 | goto _3 144 | } 145 | bin.Xsqlite3_exec(tls, (*bin.Xsqlite3)(_db), str(175), nil, nil, nil) 146 | if Xall_stop != 0 { 147 | bin.Xsqlite3_close(tls, (*bin.Xsqlite3)(_db)) 148 | goto _1 149 | } 150 | _rc = bin.Xsqlite3_exec(tls, (*bin.Xsqlite3)(_db), str(198), nil, nil, nil) 151 | bin.Xsqlite3_close(tls, (*bin.Xsqlite3)(_db)) 152 | goto _0 153 | _1: 154 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(234), _id) 155 | return nil 156 | 157 | _ = _rc 158 | panic(0) 159 | } 160 | 161 | // C comment 162 | // /* 163 | // ** When this variable becomes non-zero, all threads stop 164 | // ** what they are doing. 165 | // */ 166 | var Xall_stop int32 167 | 168 | func bool2int(b bool) int32 { 169 | if b { 170 | return 1 171 | } 172 | return 0 173 | } 174 | func bug20530(interface{}) {} //TODO remove when https://github.com/golang/go/issues/20530 is fixed. 175 | func init() { nzf32 *= -1; nzf64 *= -1 } 176 | 177 | var inf = math.Inf(1) 178 | var nzf32 float32 // -0.0 179 | var nzf64 float64 // -0.0 180 | func elem0(a *uint64, index uintptr) *uint64 { 181 | return (*uint64)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 8*index)) 182 | } 183 | func postInc1(p *int32, d int32) int32 { v := *p; *p += d; return v } 184 | func str(n int) *int8 { return (*int8)(unsafe.Pointer(&strTab[n])) } 185 | func wstr(n int) *int32 { return (*int32)(unsafe.Pointer(&strTab[n])) } 186 | 187 | var strTab = []byte("test.db\x00:memory:\x00%s-journal\x00unable to initialize database\x0a\x00CREATE TABLE t1(x);\x00cannot create table t1: %d\x0a\x00Everything seems ok.\x0a\x00We hit an error.\x0a\x00Starting worker %d\x0a\x00%d: %d\x0a\x00PRAGMA synchronous=OFF\x00INSERT INTO t1 VALUES('bogus data')\x00Worker %d finished\x0a\x00") 188 | -------------------------------------------------------------------------------- /z_linux_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Sqlite Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sqlite 6 | 7 | import ( 8 | "bytes" 9 | "io/ioutil" 10 | "os" 11 | "os/exec" 12 | "path/filepath" 13 | "testing" 14 | ) 15 | 16 | func TestMP(t *testing.T) { 17 | dir, err := ioutil.TempDir("", "sqlite-test-") 18 | if err != nil { 19 | t.Fatal(err) 20 | } 21 | 22 | defer func() { 23 | if err := os.RemoveAll(dir); err != nil { 24 | t.Fatal(err) 25 | } 26 | }() 27 | 28 | wd, err := os.Getwd() 29 | if err != nil { 30 | t.Fatal(err) 31 | } 32 | 33 | defer func() { 34 | if err := os.Chdir(wd); err != nil { 35 | t.Fatal(err) 36 | } 37 | }() 38 | 39 | if err := os.Chdir(dir); err != nil { 40 | t.Fatal(err) 41 | } 42 | 43 | if out, err := exec.Command("go", "build", "-o", "mptest", "github.com/cznic/sqlite/internal/mptest").CombinedOutput(); err != nil { 44 | t.Fatalf("go build mptest: %s\n%s", err, out) 45 | } 46 | 47 | pat := filepath.Join(wd, filepath.FromSlash("testdata/mptest"), "*.test") 48 | m, err := filepath.Glob(pat) 49 | if err != nil { 50 | t.Fatal(err) 51 | } 52 | 53 | if len(m) == 0 { 54 | t.Fatalf("%s: no files", pat) 55 | } 56 | 57 | nm := filepath.FromSlash("./mptest") 58 | for _, v := range m { 59 | os.Remove("db") 60 | out, err := exec.Command(nm, "db", v).CombinedOutput() 61 | t.Logf("%s", out) 62 | if err != nil { 63 | t.Fatal(err) 64 | } 65 | } 66 | } 67 | 68 | func TestThread1(t *testing.T) { 69 | dir, err := ioutil.TempDir("", "sqlite-test-") 70 | if err != nil { 71 | t.Fatal(err) 72 | } 73 | 74 | defer func() { 75 | if err := os.RemoveAll(dir); err != nil { 76 | t.Fatal(err) 77 | } 78 | }() 79 | 80 | wd, err := os.Getwd() 81 | if err != nil { 82 | t.Fatal(err) 83 | } 84 | 85 | defer func() { 86 | if err := os.Chdir(wd); err != nil { 87 | t.Fatal(err) 88 | } 89 | }() 90 | 91 | if err := os.Chdir(dir); err != nil { 92 | t.Fatal(err) 93 | } 94 | 95 | if out, err := exec.Command("go", "build", "-o", "threadtest1", "github.com/cznic/sqlite/internal/threadtest1").CombinedOutput(); err != nil { 96 | t.Fatalf("go build mptest: %s\n%s", err, out) 97 | } 98 | 99 | out, err := exec.Command("./threadtest1", "10").CombinedOutput() 100 | t.Logf("%s", out) 101 | if err != nil { 102 | t.Fatal(err) 103 | } 104 | } 105 | 106 | func TestThread2(t *testing.T) { 107 | dir, err := ioutil.TempDir("", "sqlite-test-") 108 | if err != nil { 109 | t.Fatal(err) 110 | } 111 | 112 | defer func() { 113 | if err := os.RemoveAll(dir); err != nil { 114 | t.Fatal(err) 115 | } 116 | }() 117 | 118 | wd, err := os.Getwd() 119 | if err != nil { 120 | t.Fatal(err) 121 | } 122 | 123 | defer func() { 124 | if err := os.Chdir(wd); err != nil { 125 | t.Fatal(err) 126 | } 127 | }() 128 | 129 | if err := os.Chdir(dir); err != nil { 130 | t.Fatal(err) 131 | } 132 | 133 | if out, err := exec.Command("go", "build", "-o", "threadtest2", "github.com/cznic/sqlite/internal/threadtest2").CombinedOutput(); err != nil { 134 | t.Fatalf("go build mptest: %s\n%s", err, out) 135 | } 136 | 137 | out, err := exec.Command("./threadtest2").CombinedOutput() 138 | t.Logf("%s", out) 139 | if err != nil { 140 | t.Fatal(err) 141 | } 142 | } 143 | 144 | func TestThread3(t *testing.T) { 145 | t.Log("TODO") 146 | return //TODO- 147 | 148 | //TODO sqlite3.c:142510: sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame)); -> fatal error: bad pointer in write barrier 149 | dir, err := ioutil.TempDir("", "sqlite-test-") 150 | if err != nil { 151 | t.Fatal(err) 152 | } 153 | 154 | defer func() { 155 | if err := os.RemoveAll(dir); err != nil { 156 | t.Fatal(err) 157 | } 158 | }() 159 | 160 | wd, err := os.Getwd() 161 | if err != nil { 162 | t.Fatal(err) 163 | } 164 | 165 | defer func() { 166 | if err := os.Chdir(wd); err != nil { 167 | t.Fatal(err) 168 | } 169 | }() 170 | 171 | if err := os.Chdir(dir); err != nil { 172 | t.Fatal(err) 173 | } 174 | 175 | s := []string{"build", "-o", "threadtest3"} 176 | if *memTrace { 177 | s = append(s, "-tags", "memory.trace", "-race") 178 | } 179 | if out, err := exec.Command("go", append(s, "github.com/cznic/sqlite/internal/threadtest3")...).CombinedOutput(); err != nil { 180 | t.Fatalf("go build mptest: %s\n%s", err, out) 181 | } 182 | 183 | for _, opts := range [][]string{ 184 | {"walthread1"}, 185 | {"walthread2"}, 186 | {"walthread3"}, 187 | {"walthread4"}, 188 | {"walthread5"}, 189 | {"cgt_pager_1"}, 190 | {"dynamic_triggers"}, 191 | {"checkpoint_starvation_1"}, 192 | {"checkpoint_starvation_2"}, 193 | {"create_drop_index_1"}, 194 | {"lookaside1"}, 195 | {"vacuum1"}, 196 | {"stress1"}, 197 | {"stress2"}, 198 | } { 199 | out, err := exec.Command("./threadtest3", opts...).CombinedOutput() 200 | t.Logf("%v\n%s", opts, out) 201 | if err != nil { 202 | t.Fatal(err) 203 | } 204 | 205 | if bytes.Contains(out, []byte("fault address")) || 206 | bytes.Contains(out, []byte("data race")) || 207 | bytes.Contains(out, []byte("RACE")) { 208 | t.Fatal("fault") 209 | } 210 | } 211 | } 212 | 213 | func TestThread4(t *testing.T) { 214 | cases := 0 215 | dir, err := ioutil.TempDir("", "sqlite-test-") 216 | if err != nil { 217 | t.Fatal(err) 218 | } 219 | 220 | defer func() { 221 | if err := os.RemoveAll(dir); err != nil { 222 | t.Fatal(err) 223 | } 224 | }() 225 | 226 | wd, err := os.Getwd() 227 | if err != nil { 228 | t.Fatal(err) 229 | } 230 | 231 | defer func() { 232 | if err := os.Chdir(wd); err != nil { 233 | t.Fatal(err) 234 | } 235 | }() 236 | 237 | if err := os.Chdir(dir); err != nil { 238 | t.Fatal(err) 239 | } 240 | 241 | s := []string{"build", "-o", "threadtest4"} 242 | if *memTrace { 243 | s = append(s, "-tags", "memory.trace", "-race") 244 | } 245 | if out, err := exec.Command("go", append(s, "github.com/cznic/sqlite/internal/threadtest4")...).CombinedOutput(); err != nil { 246 | t.Fatalf("go build mptest: %s\n%s", err, out) 247 | } 248 | 249 | for _, opts := range [][]string{ 250 | {}, 251 | {"-wal"}, 252 | {"-serialized"}, 253 | {"-serialized", "-wal"}, 254 | {"--multithread"}, 255 | {"--multithread", "-wal"}, 256 | {"--multithread", "-serialized"}, 257 | {"--multithread", "-serialized", "-wal"}, 258 | } { 259 | out, err := exec.Command("./threadtest4", append(opts, "5")...).CombinedOutput() 260 | t.Logf("%v\n%s", opts, out) 261 | if err != nil { 262 | t.Fatal(err) 263 | } 264 | 265 | if bytes.Contains(out, []byte("fault address")) || 266 | bytes.Contains(out, []byte("data race")) || 267 | bytes.Contains(out, []byte("RACE")) { 268 | t.Fatalf("case %v: fault", cases) 269 | } 270 | cases++ 271 | } 272 | t.Logf("cases: %v", cases) 273 | } 274 | -------------------------------------------------------------------------------- /all_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Sqlite Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sqlite 6 | 7 | import ( 8 | "bytes" 9 | "database/sql" 10 | "flag" 11 | "fmt" 12 | "io/ioutil" 13 | "os" 14 | "path" 15 | "path/filepath" 16 | "runtime" 17 | "strings" 18 | "testing" 19 | "time" 20 | ) 21 | 22 | func caller(s string, va ...interface{}) { 23 | if s == "" { 24 | s = strings.Repeat("%v ", len(va)) 25 | } 26 | _, fn, fl, _ := runtime.Caller(2) 27 | fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl) 28 | fmt.Fprintf(os.Stderr, s, va...) 29 | fmt.Fprintln(os.Stderr) 30 | _, fn, fl, _ = runtime.Caller(1) 31 | fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl) 32 | fmt.Fprintln(os.Stderr) 33 | os.Stderr.Sync() 34 | } 35 | 36 | func dbg(s string, va ...interface{}) { 37 | if s == "" { 38 | s = strings.Repeat("%v ", len(va)) 39 | } 40 | _, fn, fl, _ := runtime.Caller(1) 41 | fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl) 42 | fmt.Fprintf(os.Stderr, s, va...) 43 | fmt.Fprintln(os.Stderr) 44 | os.Stderr.Sync() 45 | } 46 | 47 | func TODO(...interface{}) string { //TODOOK 48 | _, fn, fl, _ := runtime.Caller(1) 49 | return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK 50 | } 51 | 52 | func use(...interface{}) {} 53 | 54 | func init() { 55 | use(caller, dbg, TODO) //TODOOK 56 | } 57 | 58 | // ============================================================================ 59 | 60 | var ( 61 | memTrace = flag.Bool("memory.trace", false, "") 62 | recsPerSec = flag.Bool("recs_per_sec_as_mbps", false, "Show records per second as MB/s.") 63 | ) 64 | 65 | func tempDB(t testing.TB) (string, *sql.DB) { 66 | dir, err := ioutil.TempDir("", "sqlite-test-") 67 | if err != nil { 68 | t.Fatal(err) 69 | } 70 | 71 | db, err := sql.Open(driverName, filepath.Join(dir, "tmp.db")) 72 | if err != nil { 73 | os.RemoveAll(dir) 74 | t.Fatal(err) 75 | } 76 | 77 | return dir, db 78 | } 79 | 80 | func TestScalar(t *testing.T) { 81 | dir, db := tempDB(t) 82 | 83 | defer func() { 84 | db.Close() 85 | os.RemoveAll(dir) 86 | }() 87 | 88 | t1 := time.Date(2017, 4, 20, 1, 2, 3, 56789, time.UTC) 89 | t2 := time.Date(2018, 5, 21, 2, 3, 4, 98765, time.UTC) 90 | r, err := db.Exec(` 91 | create table t(i int, f double, b bool, s text, t time); 92 | insert into t values(12, 3.14, ?, "foo", ?), (34, 2.78, ?, "bar", ?); 93 | `, 94 | true, t1, 95 | false, t2, 96 | ) 97 | if err != nil { 98 | t.Fatal(err) 99 | } 100 | 101 | n, err := r.RowsAffected() 102 | if err != nil { 103 | t.Fatal(err) 104 | } 105 | 106 | if g, e := n, int64(2); g != e { 107 | t.Fatal(g, e) 108 | } 109 | 110 | rows, err := db.Query("select * from t") 111 | if err != nil { 112 | t.Fatal(err) 113 | } 114 | 115 | type rec struct { 116 | i int 117 | f float64 118 | b bool 119 | s string 120 | t string 121 | } 122 | var a []rec 123 | for rows.Next() { 124 | var r rec 125 | if err := rows.Scan(&r.i, &r.f, &r.b, &r.s, &r.t); err != nil { 126 | t.Fatal(err) 127 | } 128 | 129 | a = append(a, r) 130 | } 131 | if err := rows.Err(); err != nil { 132 | t.Fatal(err) 133 | } 134 | 135 | if g, e := len(a), 2; g != e { 136 | t.Fatal(g, e) 137 | } 138 | 139 | if g, e := a[0], (rec{12, 3.14, true, "foo", t1.String()}); g != e { 140 | t.Fatal(g, e) 141 | } 142 | 143 | if g, e := a[1], (rec{34, 2.78, false, "bar", t2.String()}); g != e { 144 | t.Fatal(g, e) 145 | } 146 | } 147 | 148 | func TestBlob(t *testing.T) { 149 | dir, db := tempDB(t) 150 | 151 | defer func() { 152 | db.Close() 153 | os.RemoveAll(dir) 154 | }() 155 | 156 | b1 := []byte(time.Now().String()) 157 | b2 := []byte("\x00foo\x00bar\x00") 158 | if _, err := db.Exec(` 159 | create table t(b blob); 160 | insert into t values(?), (?); 161 | `, b1, b2, 162 | ); err != nil { 163 | t.Fatal(err) 164 | } 165 | 166 | rows, err := db.Query("select * from t") 167 | if err != nil { 168 | t.Fatal(err) 169 | } 170 | 171 | type rec struct { 172 | b []byte 173 | } 174 | var a []rec 175 | for rows.Next() { 176 | var r rec 177 | if err := rows.Scan(&r.b); err != nil { 178 | t.Fatal(err) 179 | } 180 | 181 | a = append(a, r) 182 | } 183 | if err := rows.Err(); err != nil { 184 | t.Fatal(err) 185 | } 186 | 187 | if g, e := len(a), 2; g != e { 188 | t.Fatal(g, e) 189 | } 190 | 191 | if g, e := a[0].b, b1; !bytes.Equal(g, e) { 192 | t.Fatal(g, e) 193 | } 194 | 195 | if g, e := a[1].b, b2; !bytes.Equal(g, e) { 196 | t.Fatal(g, e) 197 | } 198 | } 199 | 200 | func BenchmarkInsertMemory(b *testing.B) { 201 | db, err := sql.Open(driverName, "file::memory:") 202 | if err != nil { 203 | b.Fatal(err) 204 | } 205 | 206 | defer func() { 207 | db.Close() 208 | }() 209 | 210 | if _, err := db.Exec(` 211 | create table t(i int); 212 | begin; 213 | `); err != nil { 214 | b.Fatal(err) 215 | } 216 | 217 | s, err := db.Prepare("insert into t values(?)") 218 | if err != nil { 219 | b.Fatal(err) 220 | } 221 | 222 | b.ResetTimer() 223 | for i := 0; i < b.N; i++ { 224 | if _, err := s.Exec(int64(i)); err != nil { 225 | b.Fatal(err) 226 | } 227 | } 228 | b.StopTimer() 229 | if *recsPerSec { 230 | b.SetBytes(1e6) 231 | } 232 | if _, err := db.Exec(`commit;`); err != nil { 233 | b.Fatal(err) 234 | } 235 | } 236 | 237 | func BenchmarkNextMemory(b *testing.B) { 238 | db, err := sql.Open(driverName, "file::memory:") 239 | if err != nil { 240 | b.Fatal(err) 241 | } 242 | 243 | defer func() { 244 | db.Close() 245 | }() 246 | 247 | if _, err := db.Exec(` 248 | create table t(i int); 249 | begin; 250 | `); err != nil { 251 | b.Fatal(err) 252 | } 253 | 254 | s, err := db.Prepare("insert into t values(?)") 255 | if err != nil { 256 | b.Fatal(err) 257 | } 258 | 259 | defer s.Close() 260 | 261 | for i := 0; i < b.N; i++ { 262 | if _, err := s.Exec(int64(i)); err != nil { 263 | b.Fatal(err) 264 | } 265 | } 266 | if _, err := db.Exec("commit"); err != nil { 267 | b.Fatal(err) 268 | } 269 | 270 | r, err := db.Query("select * from t") 271 | if err != nil { 272 | 273 | } 274 | 275 | defer r.Close() 276 | 277 | b.ResetTimer() 278 | for i := 0; i < b.N; i++ { 279 | if !r.Next() { 280 | b.Fatal(err) 281 | } 282 | } 283 | b.StopTimer() 284 | if *recsPerSec { 285 | b.SetBytes(1e6) 286 | } 287 | } 288 | 289 | // https://github.com/cznic/sqlite/issues/11 290 | func TestIssue11(t *testing.T) { 291 | const N = 6570 292 | dir, db := tempDB(t) 293 | 294 | defer func() { 295 | db.Close() 296 | os.RemoveAll(dir) 297 | }() 298 | 299 | if _, err := db.Exec(` 300 | CREATE TABLE t1 (t INT); 301 | BEGIN; 302 | `, 303 | ); err != nil { 304 | t.Fatal(err) 305 | } 306 | 307 | for i := 0; i < N; i++ { 308 | if _, err := db.Exec("INSERT INTO t1 (t) VALUES (?)", i); err != nil { 309 | t.Fatalf("#%v: %v", i, err) 310 | } 311 | } 312 | if _, err := db.Exec("COMMIT;"); err != nil { 313 | t.Fatal(err) 314 | } 315 | } 316 | 317 | // https://github.com/cznic/sqlite/issues/12 318 | func TestMemDB(t *testing.T) { 319 | // Verify we can create out-of-the heap memory DB instance. 320 | db, err := sql.Open(driverName, "file::memory:") 321 | if err != nil { 322 | t.Fatal(err) 323 | } 324 | 325 | defer func() { 326 | db.Close() 327 | }() 328 | 329 | v := strings.Repeat("a", 1024) 330 | if _, err := db.Exec(` 331 | create table t(s string); 332 | begin; 333 | `); err != nil { 334 | t.Fatal(err) 335 | } 336 | 337 | s, err := db.Prepare("insert into t values(?)") 338 | if err != nil { 339 | t.Fatal(err) 340 | } 341 | 342 | // Heap used to be fixed at 32MB. 343 | for i := 0; i < (64<<20)/len(v); i++ { 344 | if _, err := s.Exec(v); err != nil { 345 | t.Fatalf("%v * %v= %v: %v", i, len(v), i*len(v), err) 346 | } 347 | } 348 | if _, err := db.Exec(`commit;`); err != nil { 349 | t.Fatal(err) 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /internal/sqlite.org/sqlite-src-3190300/test/threadtest1.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** 2002 January 15 3 | ** 4 | ** The author disclaims copyright to this source code. In place of 5 | ** a legal notice, here is a blessing: 6 | ** 7 | ** May you do good and not evil. 8 | ** May you find forgiveness for yourself and forgive others. 9 | ** May you share freely, never taking more than you give. 10 | ** 11 | ************************************************************************* 12 | ** This file implements a simple standalone program used to test whether 13 | ** or not the SQLite library is threadsafe. 14 | ** 15 | ** Testing the thread safety of SQLite is difficult because there are very 16 | ** few places in the code that are even potentially unsafe, and those 17 | ** places execute for very short periods of time. So even if the library 18 | ** is compiled with its mutexes disabled, it is likely to work correctly 19 | ** in a multi-threaded program most of the time. 20 | ** 21 | ** This file is NOT part of the standard SQLite library. It is used for 22 | ** testing only. 23 | */ 24 | #include "sqlite.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | /* 33 | ** Enable for tracing 34 | */ 35 | static int verbose = 0; 36 | 37 | /* 38 | ** Come here to die. 39 | */ 40 | static void Exit(int rc){ 41 | exit(rc); 42 | } 43 | 44 | extern char *sqlite3_mprintf(const char *zFormat, ...); 45 | extern char *sqlite3_vmprintf(const char *zFormat, va_list); 46 | 47 | /* 48 | ** When a lock occurs, yield. 49 | */ 50 | static int db_is_locked(void *NotUsed, int iCount){ 51 | /* sched_yield(); */ 52 | if( verbose ) printf("BUSY %s #%d\n", (char*)NotUsed, iCount); 53 | usleep(100); 54 | return iCount<40000; 55 | } 56 | 57 | /* 58 | ** Used to accumulate query results by db_query() 59 | */ 60 | struct QueryResult { 61 | const char *zFile; /* Filename - used for error reporting */ 62 | int nElem; /* Number of used entries in azElem[] */ 63 | int nAlloc; /* Number of slots allocated for azElem[] */ 64 | char **azElem; /* The result of the query */ 65 | }; 66 | 67 | /* 68 | ** The callback function for db_query 69 | */ 70 | static int db_query_callback( 71 | void *pUser, /* Pointer to the QueryResult structure */ 72 | int nArg, /* Number of columns in this result row */ 73 | char **azArg, /* Text of data in all columns */ 74 | char **NotUsed /* Names of the columns */ 75 | ){ 76 | struct QueryResult *pResult = (struct QueryResult*)pUser; 77 | int i; 78 | if( pResult->nElem + nArg >= pResult->nAlloc ){ 79 | if( pResult->nAlloc==0 ){ 80 | pResult->nAlloc = nArg+1; 81 | }else{ 82 | pResult->nAlloc = pResult->nAlloc*2 + nArg + 1; 83 | } 84 | pResult->azElem = realloc( pResult->azElem, pResult->nAlloc*sizeof(char*)); 85 | if( pResult->azElem==0 ){ 86 | fprintf(stdout,"%s: malloc failed\n", pResult->zFile); 87 | return 1; 88 | } 89 | } 90 | if( azArg==0 ) return 0; 91 | for(i=0; iazElem[pResult->nElem++] = 93 | sqlite3_mprintf("%s",azArg[i] ? azArg[i] : ""); 94 | } 95 | return 0; 96 | } 97 | 98 | /* 99 | ** Execute a query against the database. NULL values are returned 100 | ** as an empty string. The list is terminated by a single NULL pointer. 101 | */ 102 | char **db_query(sqlite *db, const char *zFile, const char *zFormat, ...){ 103 | char *zSql; 104 | int rc; 105 | char *zErrMsg = 0; 106 | va_list ap; 107 | struct QueryResult sResult; 108 | va_start(ap, zFormat); 109 | zSql = sqlite3_vmprintf(zFormat, ap); 110 | va_end(ap); 111 | memset(&sResult, 0, sizeof(sResult)); 112 | sResult.zFile = zFile; 113 | if( verbose ) printf("QUERY %s: %s\n", zFile, zSql); 114 | rc = sqlite3_exec(db, zSql, db_query_callback, &sResult, &zErrMsg); 115 | if( rc==SQLITE_SCHEMA ){ 116 | if( zErrMsg ) free(zErrMsg); 117 | rc = sqlite3_exec(db, zSql, db_query_callback, &sResult, &zErrMsg); 118 | } 119 | if( verbose ) printf("DONE %s %s\n", zFile, zSql); 120 | if( zErrMsg ){ 121 | fprintf(stdout,"%s: query failed: %s - %s\n", zFile, zSql, zErrMsg); 122 | free(zErrMsg); 123 | free(zSql); 124 | Exit(1); 125 | } 126 | sqlite3_free(zSql); 127 | if( sResult.azElem==0 ){ 128 | db_query_callback(&sResult, 0, 0, 0); 129 | } 130 | sResult.azElem[sResult.nElem] = 0; 131 | return sResult.azElem; 132 | } 133 | 134 | /* 135 | ** Execute an SQL statement. 136 | */ 137 | void db_execute(sqlite *db, const char *zFile, const char *zFormat, ...){ 138 | char *zSql; 139 | int rc; 140 | char *zErrMsg = 0; 141 | va_list ap; 142 | va_start(ap, zFormat); 143 | zSql = sqlite3_vmprintf(zFormat, ap); 144 | va_end(ap); 145 | if( verbose ) printf("EXEC %s: %s\n", zFile, zSql); 146 | do{ 147 | rc = sqlite3_exec(db, zSql, 0, 0, &zErrMsg); 148 | }while( rc==SQLITE_BUSY ); 149 | if( verbose ) printf("DONE %s: %s\n", zFile, zSql); 150 | if( zErrMsg ){ 151 | fprintf(stdout,"%s: command failed: %s - %s\n", zFile, zSql, zErrMsg); 152 | free(zErrMsg); 153 | sqlite3_free(zSql); 154 | Exit(1); 155 | } 156 | sqlite3_free(zSql); 157 | } 158 | 159 | /* 160 | ** Free the results of a db_query() call. 161 | */ 162 | void db_query_free(char **az){ 163 | int i; 164 | for(i=0; az[i]; i++){ 165 | sqlite3_free(az[i]); 166 | } 167 | free(az); 168 | } 169 | 170 | /* 171 | ** Check results 172 | */ 173 | void db_check(const char *zFile, const char *zMsg, char **az, ...){ 174 | va_list ap; 175 | int i; 176 | char *z; 177 | va_start(ap, az); 178 | for(i=0; (z = va_arg(ap, char*))!=0; i++){ 179 | if( az[i]==0 || strcmp(az[i],z)!=0 ){ 180 | fprintf(stdout,"%s: %s: bad result in column %d: %s\n", 181 | zFile, zMsg, i+1, az[i]); 182 | db_query_free(az); 183 | Exit(1); 184 | } 185 | } 186 | va_end(ap); 187 | db_query_free(az); 188 | } 189 | 190 | pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 191 | pthread_cond_t sig = PTHREAD_COND_INITIALIZER; 192 | int thread_cnt = 0; 193 | 194 | static void *worker_bee(void *pArg){ 195 | const char *zFilename = (char*)pArg; 196 | char *azErr; 197 | int i, cnt; 198 | int t = atoi(zFilename); 199 | char **az; 200 | sqlite *db; 201 | 202 | pthread_mutex_lock(&lock); 203 | thread_cnt++; 204 | pthread_mutex_unlock(&lock); 205 | printf("%s: START\n", zFilename); 206 | fflush(stdout); 207 | for(cnt=0; cnt<10; cnt++){ 208 | sqlite3_open(&zFilename[2], &db); 209 | if( db==0 ){ 210 | fprintf(stdout,"%s: can't open\n", zFilename); 211 | Exit(1); 212 | } 213 | sqlite3_busy_handler(db, db_is_locked, zFilename); 214 | db_execute(db, zFilename, "CREATE TABLE t%d(a,b,c);", t); 215 | for(i=1; i<=100; i++){ 216 | db_execute(db, zFilename, "INSERT INTO t%d VALUES(%d,%d,%d);", 217 | t, i, i*2, i*i); 218 | } 219 | az = db_query(db, zFilename, "SELECT count(*) FROM t%d", t); 220 | db_check(zFilename, "tX size", az, "100", 0); 221 | az = db_query(db, zFilename, "SELECT avg(b) FROM t%d", t); 222 | db_check(zFilename, "tX avg", az, "101.0", 0); 223 | db_execute(db, zFilename, "DELETE FROM t%d WHERE a>50", t); 224 | az = db_query(db, zFilename, "SELECT avg(b) FROM t%d", t); 225 | db_check(zFilename, "tX avg2", az, "51.0", 0); 226 | for(i=1; i<=50; i++){ 227 | char z1[30], z2[30]; 228 | az = db_query(db, zFilename, "SELECT b, c FROM t%d WHERE a=%d", t, i); 229 | sprintf(z1, "%d", i*2); 230 | sprintf(z2, "%d", i*i); 231 | db_check(zFilename, "readback", az, z1, z2, 0); 232 | } 233 | db_execute(db, zFilename, "DROP TABLE t%d;", t); 234 | sqlite3_close(db); 235 | } 236 | printf("%s: END\n", zFilename); 237 | /* unlink(zFilename); */ 238 | fflush(stdout); 239 | pthread_mutex_lock(&lock); 240 | thread_cnt--; 241 | if( thread_cnt<=0 ){ 242 | pthread_cond_signal(&sig); 243 | } 244 | pthread_mutex_unlock(&lock); 245 | return 0; 246 | } 247 | 248 | int main(int argc, char **argv){ 249 | char *zFile; 250 | int i, n; 251 | pthread_t id; 252 | if( argc>2 && strcmp(argv[1], "-v")==0 ){ 253 | verbose = 1; 254 | argc--; 255 | argv++; 256 | } 257 | if( argc<2 || (n=atoi(argv[1]))<1 ) n = 10; 258 | for(i=0; i0 ){ 280 | pthread_cond_wait(&sig, &lock); 281 | } 282 | pthread_mutex_unlock(&lock); 283 | for(i=0; i int32(2)) && (crt.Xstrcmp(tls, *elem0(_argv, uintptr(1)), str(0)) == int32(0)) { 80 | _verbose = int32(1) 81 | bug20530(_verbose) 82 | _argc -= 1 83 | *(*uintptr)(unsafe.Pointer(&_argv)) += uintptr(4) 84 | } 85 | if (_argc < int32(2)) || (store1(&_n, crt.Xatoi(tls, *elem0(_argv, uintptr(1)))) < int32(1)) { 86 | _n = int32(10) 87 | } 88 | _i = int32(0) 89 | _4: 90 | if _i >= _n { 91 | goto _7 92 | } 93 | crt.Xsprintf(tls, (*int8)(unsafe.Pointer(&_2_zBuf)), str(3), (_i+int32(1))/int32(2)) 94 | crt.Xunlink(tls, (*int8)(unsafe.Pointer(&_2_zBuf))) 95 | _i += 1 96 | goto _4 97 | _7: 98 | _i = int32(0) 99 | _8: 100 | if _i >= _n { 101 | goto _11 102 | } 103 | _zFile = bin.Xsqlite3_mprintf(tls, str(13), (_i%int32(2))+int32(1), (_i+int32(2))/int32(2)) 104 | if (_i % int32(2)) == int32(0) { 105 | _4_zDb = elem2(_zFile, uintptr(2)) 106 | _4_zJournal = bin.Xsqlite3_mprintf(tls, str(26), unsafe.Pointer(_4_zDb)) 107 | crt.Xunlink(tls, _4_zDb) 108 | crt.Xunlink(tls, _4_zJournal) 109 | crt.Xfree(tls, unsafe.Pointer(_4_zJournal)) 110 | } 111 | crt.Xpthread_create(tls, &_id, nil, _worker_bee, unsafe.Pointer(_zFile)) 112 | crt.Xpthread_detach(tls, _id) 113 | _i += 1 114 | goto _8 115 | _11: 116 | crt.Xpthread_mutex_lock(tls, &Xlock) 117 | _13: 118 | if Xthread_cnt > int32(0) { 119 | crt.Xpthread_cond_wait(tls, &Xsig, &Xlock) 120 | goto _13 121 | } 122 | crt.Xpthread_mutex_unlock(tls, &Xlock) 123 | _i = int32(0) 124 | _15: 125 | if _i >= _n { 126 | goto _18 127 | } 128 | crt.Xsprintf(tls, (*int8)(unsafe.Pointer(&_6_zBuf)), str(3), (_i+int32(1))/int32(2)) 129 | crt.Xunlink(tls, (*int8)(unsafe.Pointer(&_6_zBuf))) 130 | _i += 1 131 | goto _15 132 | _18: 133 | return int32(0) 134 | 135 | _ = _2_zBuf 136 | _ = _6_zBuf 137 | panic(0) 138 | } 139 | 140 | // C comment 141 | // /* 142 | // ** Enable for tracing 143 | // */ 144 | var _verbose int32 145 | 146 | func _worker_bee(tls *crt.TLS, _pArg unsafe.Pointer) (r0 unsafe.Pointer) { 147 | var _i, _cnt, _t int32 148 | var _zFilename, _azErr *int8 149 | var _db unsafe.Pointer 150 | var _az **int8 151 | var _4_z1, _4_z2 [30]int8 152 | _zFilename = (*int8)(_pArg) 153 | _t = crt.Xatoi(tls, _zFilename) 154 | crt.Xpthread_mutex_lock(tls, &Xlock) 155 | Xthread_cnt += 1 156 | crt.Xpthread_mutex_unlock(tls, &Xlock) 157 | crt.Xprintf(tls, str(37), unsafe.Pointer(_zFilename)) 158 | crt.Xfflush(tls, (*crt.XFILE)(Xstdout)) 159 | _cnt = int32(0) 160 | _0: 161 | if _cnt >= int32(10) { 162 | goto _3 163 | } 164 | bin.Xsqlite3_open(tls, elem2(_zFilename, uintptr(2)), (**bin.Xsqlite3)(unsafe.Pointer(&_db))) 165 | if _db == nil { 166 | crt.Xfprintf(tls, (*crt.XFILE)(Xstdout), str(48), unsafe.Pointer(_zFilename)) 167 | _Exit(tls, int32(1)) 168 | } 169 | bin.Xsqlite3_busy_handler(tls, (*bin.Xsqlite3)(_db), _db_is_locked, unsafe.Pointer(_zFilename)) 170 | Xdb_execute(tls, _db, _zFilename, str(64), _t) 171 | _i = int32(1) 172 | _5: 173 | if _i > int32(100) { 174 | goto _8 175 | } 176 | Xdb_execute(tls, _db, _zFilename, str(89), _t, _i, _i*int32(2), _i*_i) 177 | _i += 1 178 | goto _5 179 | _8: 180 | _az = Xdb_query(tls, _db, _zFilename, str(123), _t) 181 | Xdb_check(tls, _zFilename, str(148), _az, unsafe.Pointer(str(156)), int32(0)) 182 | _az = Xdb_query(tls, _db, _zFilename, str(160), _t) 183 | Xdb_check(tls, _zFilename, str(183), _az, unsafe.Pointer(str(190)), int32(0)) 184 | Xdb_execute(tls, _db, _zFilename, str(196), _t) 185 | _az = Xdb_query(tls, _db, _zFilename, str(160), _t) 186 | Xdb_check(tls, _zFilename, str(223), _az, unsafe.Pointer(str(231)), int32(0)) 187 | _i = int32(1) 188 | _9: 189 | if _i > int32(50) { 190 | goto _12 191 | } 192 | _az = Xdb_query(tls, _db, _zFilename, str(236), _t, _i) 193 | crt.Xsprintf(tls, (*int8)(unsafe.Pointer(&_4_z1)), str(268), _i*int32(2)) 194 | crt.Xsprintf(tls, (*int8)(unsafe.Pointer(&_4_z2)), str(268), _i*_i) 195 | Xdb_check(tls, _zFilename, str(271), _az, unsafe.Pointer(&_4_z1), unsafe.Pointer(&_4_z2), int32(0)) 196 | _i += 1 197 | goto _9 198 | _12: 199 | Xdb_execute(tls, _db, _zFilename, str(280), _t) 200 | bin.Xsqlite3_close(tls, (*bin.Xsqlite3)(_db)) 201 | _cnt += 1 202 | goto _0 203 | _3: 204 | crt.Xprintf(tls, str(296), unsafe.Pointer(_zFilename)) 205 | crt.Xfflush(tls, (*crt.XFILE)(Xstdout)) 206 | crt.Xpthread_mutex_lock(tls, &Xlock) 207 | Xthread_cnt -= 1 208 | if Xthread_cnt <= int32(0) { 209 | crt.Xpthread_cond_signal(tls, &Xsig) 210 | } 211 | crt.Xpthread_mutex_unlock(tls, &Xlock) 212 | return nil 213 | 214 | _ = _azErr 215 | _ = _4_z1 216 | _ = _4_z2 217 | panic(0) 218 | } 219 | 220 | var Xlock crt.Xpthread_mutex_t 221 | 222 | var Xthread_cnt int32 223 | 224 | // C comment 225 | // /* 226 | // ** Come here to die. 227 | // */ 228 | func _Exit(tls *crt.TLS, _rc int32) { 229 | crt.Xexit(tls, _rc) 230 | } 231 | 232 | // C comment 233 | // /* 234 | // ** When a lock occurs, yield. 235 | // */ 236 | func _db_is_locked(tls *crt.TLS, _NotUsed unsafe.Pointer, _iCount int32) (r0 int32) { 237 | if _verbose != 0 { 238 | crt.Xprintf(tls, str(305), _NotUsed, _iCount) 239 | } 240 | crt.Xusleep(tls, uint32(100)) 241 | return bool2int(_iCount < int32(40000)) 242 | } 243 | 244 | // C comment 245 | // /* 246 | // ** Execute an SQL statement. 247 | // */ 248 | func Xdb_execute(tls *crt.TLS, _db unsafe.Pointer, _zFile *int8, _zFormat *int8, args ...interface{}) { 249 | var _rc int32 250 | var _zSql, _zErrMsg *int8 251 | var _ap []interface{} 252 | _zErrMsg = nil 253 | _ap = args 254 | _zSql = bin.Xsqlite3_vmprintf(tls, _zFormat, _ap) 255 | _ap = nil 256 | if _verbose != 0 { 257 | crt.Xprintf(tls, str(318), unsafe.Pointer(_zFile), unsafe.Pointer(_zSql)) 258 | } 259 | _0: 260 | _rc = bin.Xsqlite3_exec(tls, (*bin.Xsqlite3)(_db), _zSql, nil, nil, &_zErrMsg) 261 | if _rc == int32(5) { 262 | goto _0 263 | } 264 | if _verbose != 0 { 265 | crt.Xprintf(tls, str(331), unsafe.Pointer(_zFile), unsafe.Pointer(_zSql)) 266 | } 267 | if _zErrMsg != nil { 268 | crt.Xfprintf(tls, (*crt.XFILE)(Xstdout), str(344), unsafe.Pointer(_zFile), unsafe.Pointer(_zSql), unsafe.Pointer(_zErrMsg)) 269 | crt.Xfree(tls, unsafe.Pointer(_zErrMsg)) 270 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zSql)) 271 | _Exit(tls, int32(1)) 272 | } 273 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zSql)) 274 | } 275 | 276 | // C comment 277 | // /* 278 | // ** Execute a query against the database. NULL values are returned 279 | // ** as an empty string. The list is terminated by a single NULL pointer. 280 | // */ 281 | func Xdb_query(tls *crt.TLS, _db unsafe.Pointer, _zFile *int8, _zFormat *int8, args ...interface{}) (r0 **int8) { 282 | var _rc int32 283 | var _zSql, _zErrMsg *int8 284 | var _ap []interface{} 285 | var _sResult TQueryResult 286 | _zErrMsg = nil 287 | _ap = args 288 | _zSql = bin.Xsqlite3_vmprintf(tls, _zFormat, _ap) 289 | _ap = nil 290 | crt.Xmemset(tls, unsafe.Pointer(&_sResult), int32(0), uint32(16)) 291 | _sResult.XzFile = _zFile 292 | if _verbose != 0 { 293 | crt.Xprintf(tls, str(373), unsafe.Pointer(_zFile), unsafe.Pointer(_zSql)) 294 | } 295 | _rc = bin.Xsqlite3_exec(tls, (*bin.Xsqlite3)(_db), _zSql, _db_query_callback, unsafe.Pointer(&_sResult), &_zErrMsg) 296 | if _rc != int32(17) { 297 | goto _1 298 | } 299 | if _zErrMsg != nil { 300 | crt.Xfree(tls, unsafe.Pointer(_zErrMsg)) 301 | } 302 | _rc = bin.Xsqlite3_exec(tls, (*bin.Xsqlite3)(_db), _zSql, _db_query_callback, unsafe.Pointer(&_sResult), &_zErrMsg) 303 | _1: 304 | if _verbose != 0 { 305 | crt.Xprintf(tls, str(387), unsafe.Pointer(_zFile), unsafe.Pointer(_zSql)) 306 | } 307 | if _zErrMsg != nil { 308 | crt.Xfprintf(tls, (*crt.XFILE)(Xstdout), str(399), unsafe.Pointer(_zFile), unsafe.Pointer(_zSql), unsafe.Pointer(_zErrMsg)) 309 | crt.Xfree(tls, unsafe.Pointer(_zErrMsg)) 310 | crt.Xfree(tls, unsafe.Pointer(_zSql)) 311 | _Exit(tls, int32(1)) 312 | } 313 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zSql)) 314 | if _sResult.XazElem == nil { 315 | _db_query_callback(tls, unsafe.Pointer(&_sResult), int32(0), nil, nil) 316 | } 317 | *elem0(_sResult.XazElem, uintptr(_sResult.XnElem)) = nil 318 | return _sResult.XazElem 319 | } 320 | 321 | // C comment 322 | // /* 323 | // ** The callback function for db_query 324 | // */ 325 | func _db_query_callback(tls *crt.TLS, _pUser unsafe.Pointer, _nArg int32, _azArg **int8, _NotUsed **int8) (r0 int32) { 326 | var _i int32 327 | var _pResult *TQueryResult 328 | _pResult = (*TQueryResult)(_pUser) 329 | if (_pResult.XnElem + _nArg) < _pResult.XnAlloc { 330 | goto _0 331 | } 332 | if _pResult.XnAlloc == int32(0) { 333 | _pResult.XnAlloc = _nArg + int32(1) 334 | goto _2 335 | } 336 | _pResult.XnAlloc = ((_pResult.XnAlloc * int32(2)) + _nArg) + int32(1) 337 | _2: 338 | _pResult.XazElem = (**int8)(crt.Xrealloc(tls, unsafe.Pointer(_pResult.XazElem), uint32(_pResult.XnAlloc)*uint32(4))) 339 | if _pResult.XazElem == nil { 340 | crt.Xfprintf(tls, (*crt.XFILE)(Xstdout), str(426), unsafe.Pointer(_pResult.XzFile)) 341 | return int32(1) 342 | } 343 | _0: 344 | if _azArg == nil { 345 | return int32(0) 346 | } 347 | _i = int32(0) 348 | _5: 349 | if _i >= _nArg { 350 | goto _8 351 | } 352 | *elem0(_pResult.XazElem, uintptr(postInc1(&_pResult.XnElem, 1))) = bin.Xsqlite3_mprintf(tls, str(445), unsafe.Pointer(func() *int8 { 353 | if (*elem0(_azArg, uintptr(_i))) != nil { 354 | return (*elem0(_azArg, uintptr(_i))) 355 | } 356 | return str(448) 357 | }())) 358 | _i += 1 359 | goto _5 360 | _8: 361 | return int32(0) 362 | } 363 | 364 | // C comment 365 | // /* 366 | // ** Check results 367 | // */ 368 | func Xdb_check(tls *crt.TLS, _zFile *int8, _zMsg *int8, _az **int8, args ...interface{}) { 369 | var _i int32 370 | var _z *int8 371 | var _ap []interface{} 372 | _ap = args 373 | _i = int32(0) 374 | _0: 375 | if store2(&_z, (*int8)(crt.VAPointer(&_ap))) == nil { 376 | goto _3 377 | } 378 | if ((*elem0(_az, uintptr(_i))) == nil) || (crt.Xstrcmp(tls, *elem0(_az, uintptr(_i)), _z) != int32(0)) { 379 | crt.Xfprintf(tls, (*crt.XFILE)(Xstdout), str(449), unsafe.Pointer(_zFile), unsafe.Pointer(_zMsg), _i+int32(1), unsafe.Pointer(*elem0(_az, uintptr(_i)))) 380 | Xdb_query_free(tls, _az) 381 | _Exit(tls, int32(1)) 382 | } 383 | _i += 1 384 | goto _0 385 | _3: 386 | _ap = nil 387 | Xdb_query_free(tls, _az) 388 | } 389 | 390 | // C comment 391 | // /* 392 | // ** Free the results of a db_query() call. 393 | // */ 394 | func Xdb_query_free(tls *crt.TLS, _az **int8) { 395 | var _i int32 396 | _i = int32(0) 397 | _0: 398 | if (*elem0(_az, uintptr(_i))) == nil { 399 | goto _3 400 | } 401 | bin.Xsqlite3_free(tls, unsafe.Pointer(*elem0(_az, uintptr(_i)))) 402 | _i += 1 403 | goto _0 404 | _3: 405 | crt.Xfree(tls, unsafe.Pointer(_az)) 406 | } 407 | 408 | var Xsig crt.Xpthread_cond_t 409 | 410 | func bool2int(b bool) int32 { 411 | if b { 412 | return 1 413 | } 414 | return 0 415 | } 416 | func bug20530(interface{}) {} //TODO remove when https://github.com/golang/go/issues/20530 is fixed. 417 | func init() { nzf32 *= -1; nzf64 *= -1 } 418 | 419 | var inf = math.Inf(1) 420 | var nzf32 float32 // -0.0 421 | var nzf64 float64 // -0.0 422 | func elem0(a **int8, index uintptr) **int8 { 423 | return (**int8)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 4*index)) 424 | } 425 | func elem2(a *int8, index uintptr) *int8 { 426 | return (*int8)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 1*index)) 427 | } 428 | func postInc1(p *int32, d int32) int32 { v := *p; *p += d; return v } 429 | func store2(p **int8, v *int8) *int8 { *p = v; return v } 430 | func store1(p *int32, v int32) int32 { *p = v; return v } 431 | 432 | type TQueryResult struct { 433 | XzFile *int8 434 | XnElem int32 435 | XnAlloc int32 436 | XazElem **int8 437 | } // t3 struct{zFile *int8,nElem int32,nAlloc int32,azElem **int8} 438 | func str(n int) *int8 { return (*int8)(unsafe.Pointer(&strTab[n])) } 439 | func wstr(n int) *int32 { return (*int32)(unsafe.Pointer(&strTab[n])) } 440 | 441 | var strTab = []byte("-v\x00testdb-%d\x00%d.testdb-%d\x00%s-journal\x00%s: START\x0a\x00%s: can't open\x0a\x00CREATE TABLE t%d(a,b,c);\x00INSERT INTO t%d VALUES(%d,%d,%d);\x00SELECT count(*) FROM t%d\x00tX size\x00100\x00SELECT avg(b) FROM t%d\x00tX avg\x00101.0\x00DELETE FROM t%d WHERE a>50\x00tX avg2\x0051.0\x00SELECT b, c FROM t%d WHERE a=%d\x00%d\x00readback\x00DROP TABLE t%d;\x00%s: END\x0a\x00BUSY %s #%d\x0a\x00EXEC %s: %s\x0a\x00DONE %s: %s\x0a\x00%s: command failed: %s - %s\x0a\x00QUERY %s: %s\x0a\x00DONE %s %s\x0a\x00%s: query failed: %s - %s\x0a\x00%s: malloc failed\x0a\x00%s\x00\x00%s: %s: bad result in column %d: %s\x0a\x00") 442 | -------------------------------------------------------------------------------- /internal/threadtest1/threadtest1_linux_amd64.go: -------------------------------------------------------------------------------- 1 | // Code generated by ccgo. DO NOT EDIT. 2 | 3 | // threadtest1 4 | // /* 5 | // ** 2002 January 15 6 | // ** 7 | // ** The author disclaims copyright to this source code. In place of 8 | // ** a legal notice, here is a blessing: 9 | // ** 10 | // ** May you do good and not evil. 11 | // ** May you find forgiveness for yourself and forgive others. 12 | // ** May you share freely, never taking more than you give. 13 | // ** 14 | // ************************************************************************* 15 | // ** This file implements a simple standalone program used to test whether 16 | // ** or not the SQLite library is threadsafe. 17 | // ** 18 | // ** Testing the thread safety of SQLite is difficult because there are very 19 | // ** few places in the code that are even potentially unsafe, and those 20 | // ** places execute for very short periods of time. So even if the library 21 | // ** is compiled with its mutexes disabled, it is likely to work correctly 22 | // ** in a multi-threaded program most of the time. 23 | // ** 24 | // ** This file is NOT part of the standard SQLite library. It is used for 25 | // ** testing only. 26 | // */ 27 | package main 28 | 29 | import ( 30 | "math" 31 | "os" 32 | "unsafe" 33 | 34 | "github.com/cznic/ccgo/crt" 35 | "github.com/cznic/sqlite/internal/bin" 36 | ) 37 | 38 | var argv []*int8 39 | 40 | func main() { 41 | for _, v := range os.Args { 42 | argv = append(argv, (*int8)(crt.CString(v))) 43 | } 44 | argv = append(argv, nil) 45 | X_start(crt.NewTLS(), int32(len(os.Args)), &argv[0]) 46 | } 47 | 48 | func X_start(tls *crt.TLS, _argc int32, _argv **int8) { 49 | crt.X__register_stdfiles(tls, Xstdin, Xstdout, Xstderr) 50 | crt.X__builtin_exit(tls, Xmain(tls, _argc, _argv)) 51 | } 52 | 53 | var Xstdin unsafe.Pointer 54 | 55 | func init() { 56 | Xstdin = unsafe.Pointer(&X__stdfiles) 57 | } 58 | 59 | var X__stdfiles [3]unsafe.Pointer 60 | 61 | var Xstdout unsafe.Pointer 62 | 63 | func init() { 64 | Xstdout = unsafe.Pointer(uintptr(unsafe.Pointer(&X__stdfiles)) + 8) 65 | } 66 | 67 | var Xstderr unsafe.Pointer 68 | 69 | func init() { 70 | Xstderr = unsafe.Pointer(uintptr(unsafe.Pointer(&X__stdfiles)) + 16) 71 | } 72 | 73 | func Xmain(tls *crt.TLS, _argc int32, _argv **int8) (r0 int32) { 74 | var _i, _n int32 75 | var _id uint64 76 | var _zFile, _4_zDb, _4_zJournal *int8 77 | var _2_zBuf, _6_zBuf [200]int8 78 | r0 = int32(0) 79 | if (_argc > int32(2)) && (crt.Xstrcmp(tls, *elem0(_argv, uintptr(1)), str(0)) == int32(0)) { 80 | _verbose = int32(1) 81 | bug20530(_verbose) 82 | _argc -= 1 83 | *(*uintptr)(unsafe.Pointer(&_argv)) += uintptr(8) 84 | } 85 | if (_argc < int32(2)) || (store1(&_n, crt.Xatoi(tls, *elem0(_argv, uintptr(1)))) < int32(1)) { 86 | _n = int32(10) 87 | } 88 | _i = int32(0) 89 | _4: 90 | if _i >= _n { 91 | goto _7 92 | } 93 | crt.Xsprintf(tls, (*int8)(unsafe.Pointer(&_2_zBuf)), str(3), (_i+int32(1))/int32(2)) 94 | crt.Xunlink(tls, (*int8)(unsafe.Pointer(&_2_zBuf))) 95 | _i += 1 96 | goto _4 97 | _7: 98 | _i = int32(0) 99 | _8: 100 | if _i >= _n { 101 | goto _11 102 | } 103 | _zFile = bin.Xsqlite3_mprintf(tls, str(13), (_i%int32(2))+int32(1), (_i+int32(2))/int32(2)) 104 | if (_i % int32(2)) == int32(0) { 105 | _4_zDb = elem2(_zFile, uintptr(2)) 106 | _4_zJournal = bin.Xsqlite3_mprintf(tls, str(26), unsafe.Pointer(_4_zDb)) 107 | crt.Xunlink(tls, _4_zDb) 108 | crt.Xunlink(tls, _4_zJournal) 109 | crt.Xfree(tls, unsafe.Pointer(_4_zJournal)) 110 | } 111 | crt.Xpthread_create(tls, &_id, nil, _worker_bee, unsafe.Pointer(_zFile)) 112 | crt.Xpthread_detach(tls, _id) 113 | _i += 1 114 | goto _8 115 | _11: 116 | crt.Xpthread_mutex_lock(tls, &Xlock) 117 | _13: 118 | if Xthread_cnt > int32(0) { 119 | crt.Xpthread_cond_wait(tls, &Xsig, &Xlock) 120 | goto _13 121 | } 122 | crt.Xpthread_mutex_unlock(tls, &Xlock) 123 | _i = int32(0) 124 | _15: 125 | if _i >= _n { 126 | goto _18 127 | } 128 | crt.Xsprintf(tls, (*int8)(unsafe.Pointer(&_6_zBuf)), str(3), (_i+int32(1))/int32(2)) 129 | crt.Xunlink(tls, (*int8)(unsafe.Pointer(&_6_zBuf))) 130 | _i += 1 131 | goto _15 132 | _18: 133 | return int32(0) 134 | 135 | _ = _2_zBuf 136 | _ = _6_zBuf 137 | panic(0) 138 | } 139 | 140 | // C comment 141 | // /* 142 | // ** Enable for tracing 143 | // */ 144 | var _verbose int32 145 | 146 | func _worker_bee(tls *crt.TLS, _pArg unsafe.Pointer) (r0 unsafe.Pointer) { 147 | var _i, _cnt, _t int32 148 | var _zFilename, _azErr *int8 149 | var _db unsafe.Pointer 150 | var _az **int8 151 | var _4_z1, _4_z2 [30]int8 152 | _zFilename = (*int8)(_pArg) 153 | _t = crt.Xatoi(tls, _zFilename) 154 | crt.Xpthread_mutex_lock(tls, &Xlock) 155 | Xthread_cnt += 1 156 | crt.Xpthread_mutex_unlock(tls, &Xlock) 157 | crt.Xprintf(tls, str(37), unsafe.Pointer(_zFilename)) 158 | crt.Xfflush(tls, (*crt.XFILE)(Xstdout)) 159 | _cnt = int32(0) 160 | _0: 161 | if _cnt >= int32(10) { 162 | goto _3 163 | } 164 | bin.Xsqlite3_open(tls, elem2(_zFilename, uintptr(2)), (**bin.Xsqlite3)(unsafe.Pointer(&_db))) 165 | if _db == nil { 166 | crt.Xfprintf(tls, (*crt.XFILE)(Xstdout), str(48), unsafe.Pointer(_zFilename)) 167 | _Exit(tls, int32(1)) 168 | } 169 | bin.Xsqlite3_busy_handler(tls, (*bin.Xsqlite3)(_db), _db_is_locked, unsafe.Pointer(_zFilename)) 170 | Xdb_execute(tls, _db, _zFilename, str(64), _t) 171 | _i = int32(1) 172 | _5: 173 | if _i > int32(100) { 174 | goto _8 175 | } 176 | Xdb_execute(tls, _db, _zFilename, str(89), _t, _i, _i*int32(2), _i*_i) 177 | _i += 1 178 | goto _5 179 | _8: 180 | _az = Xdb_query(tls, _db, _zFilename, str(123), _t) 181 | Xdb_check(tls, _zFilename, str(148), _az, unsafe.Pointer(str(156)), int32(0)) 182 | _az = Xdb_query(tls, _db, _zFilename, str(160), _t) 183 | Xdb_check(tls, _zFilename, str(183), _az, unsafe.Pointer(str(190)), int32(0)) 184 | Xdb_execute(tls, _db, _zFilename, str(196), _t) 185 | _az = Xdb_query(tls, _db, _zFilename, str(160), _t) 186 | Xdb_check(tls, _zFilename, str(223), _az, unsafe.Pointer(str(231)), int32(0)) 187 | _i = int32(1) 188 | _9: 189 | if _i > int32(50) { 190 | goto _12 191 | } 192 | _az = Xdb_query(tls, _db, _zFilename, str(236), _t, _i) 193 | crt.Xsprintf(tls, (*int8)(unsafe.Pointer(&_4_z1)), str(268), _i*int32(2)) 194 | crt.Xsprintf(tls, (*int8)(unsafe.Pointer(&_4_z2)), str(268), _i*_i) 195 | Xdb_check(tls, _zFilename, str(271), _az, unsafe.Pointer(&_4_z1), unsafe.Pointer(&_4_z2), int32(0)) 196 | _i += 1 197 | goto _9 198 | _12: 199 | Xdb_execute(tls, _db, _zFilename, str(280), _t) 200 | bin.Xsqlite3_close(tls, (*bin.Xsqlite3)(_db)) 201 | _cnt += 1 202 | goto _0 203 | _3: 204 | crt.Xprintf(tls, str(296), unsafe.Pointer(_zFilename)) 205 | crt.Xfflush(tls, (*crt.XFILE)(Xstdout)) 206 | crt.Xpthread_mutex_lock(tls, &Xlock) 207 | Xthread_cnt -= 1 208 | if Xthread_cnt <= int32(0) { 209 | crt.Xpthread_cond_signal(tls, &Xsig) 210 | } 211 | crt.Xpthread_mutex_unlock(tls, &Xlock) 212 | return nil 213 | 214 | _ = _azErr 215 | _ = _4_z1 216 | _ = _4_z2 217 | panic(0) 218 | } 219 | 220 | var Xlock crt.Xpthread_mutex_t 221 | 222 | var Xthread_cnt int32 223 | 224 | // C comment 225 | // /* 226 | // ** Come here to die. 227 | // */ 228 | func _Exit(tls *crt.TLS, _rc int32) { 229 | crt.Xexit(tls, _rc) 230 | } 231 | 232 | // C comment 233 | // /* 234 | // ** When a lock occurs, yield. 235 | // */ 236 | func _db_is_locked(tls *crt.TLS, _NotUsed unsafe.Pointer, _iCount int32) (r0 int32) { 237 | if _verbose != 0 { 238 | crt.Xprintf(tls, str(305), _NotUsed, _iCount) 239 | } 240 | crt.Xusleep(tls, uint32(100)) 241 | return bool2int(_iCount < int32(40000)) 242 | } 243 | 244 | // C comment 245 | // /* 246 | // ** Execute an SQL statement. 247 | // */ 248 | func Xdb_execute(tls *crt.TLS, _db unsafe.Pointer, _zFile *int8, _zFormat *int8, args ...interface{}) { 249 | var _rc int32 250 | var _zSql, _zErrMsg *int8 251 | var _ap []interface{} 252 | _zErrMsg = nil 253 | _ap = args 254 | _zSql = bin.Xsqlite3_vmprintf(tls, _zFormat, _ap) 255 | _ap = nil 256 | if _verbose != 0 { 257 | crt.Xprintf(tls, str(318), unsafe.Pointer(_zFile), unsafe.Pointer(_zSql)) 258 | } 259 | _0: 260 | _rc = bin.Xsqlite3_exec(tls, (*bin.Xsqlite3)(_db), _zSql, nil, nil, &_zErrMsg) 261 | if _rc == int32(5) { 262 | goto _0 263 | } 264 | if _verbose != 0 { 265 | crt.Xprintf(tls, str(331), unsafe.Pointer(_zFile), unsafe.Pointer(_zSql)) 266 | } 267 | if _zErrMsg != nil { 268 | crt.Xfprintf(tls, (*crt.XFILE)(Xstdout), str(344), unsafe.Pointer(_zFile), unsafe.Pointer(_zSql), unsafe.Pointer(_zErrMsg)) 269 | crt.Xfree(tls, unsafe.Pointer(_zErrMsg)) 270 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zSql)) 271 | _Exit(tls, int32(1)) 272 | } 273 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zSql)) 274 | } 275 | 276 | // C comment 277 | // /* 278 | // ** Execute a query against the database. NULL values are returned 279 | // ** as an empty string. The list is terminated by a single NULL pointer. 280 | // */ 281 | func Xdb_query(tls *crt.TLS, _db unsafe.Pointer, _zFile *int8, _zFormat *int8, args ...interface{}) (r0 **int8) { 282 | var _rc int32 283 | var _zSql, _zErrMsg *int8 284 | var _ap []interface{} 285 | var _sResult TQueryResult 286 | _zErrMsg = nil 287 | _ap = args 288 | _zSql = bin.Xsqlite3_vmprintf(tls, _zFormat, _ap) 289 | _ap = nil 290 | crt.Xmemset(tls, unsafe.Pointer(&_sResult), int32(0), uint64(24)) 291 | _sResult.XzFile = _zFile 292 | if _verbose != 0 { 293 | crt.Xprintf(tls, str(373), unsafe.Pointer(_zFile), unsafe.Pointer(_zSql)) 294 | } 295 | _rc = bin.Xsqlite3_exec(tls, (*bin.Xsqlite3)(_db), _zSql, _db_query_callback, unsafe.Pointer(&_sResult), &_zErrMsg) 296 | if _rc != int32(17) { 297 | goto _1 298 | } 299 | if _zErrMsg != nil { 300 | crt.Xfree(tls, unsafe.Pointer(_zErrMsg)) 301 | } 302 | _rc = bin.Xsqlite3_exec(tls, (*bin.Xsqlite3)(_db), _zSql, _db_query_callback, unsafe.Pointer(&_sResult), &_zErrMsg) 303 | _1: 304 | if _verbose != 0 { 305 | crt.Xprintf(tls, str(387), unsafe.Pointer(_zFile), unsafe.Pointer(_zSql)) 306 | } 307 | if _zErrMsg != nil { 308 | crt.Xfprintf(tls, (*crt.XFILE)(Xstdout), str(399), unsafe.Pointer(_zFile), unsafe.Pointer(_zSql), unsafe.Pointer(_zErrMsg)) 309 | crt.Xfree(tls, unsafe.Pointer(_zErrMsg)) 310 | crt.Xfree(tls, unsafe.Pointer(_zSql)) 311 | _Exit(tls, int32(1)) 312 | } 313 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zSql)) 314 | if _sResult.XazElem == nil { 315 | _db_query_callback(tls, unsafe.Pointer(&_sResult), int32(0), nil, nil) 316 | } 317 | *elem0(_sResult.XazElem, uintptr(_sResult.XnElem)) = nil 318 | return _sResult.XazElem 319 | } 320 | 321 | // C comment 322 | // /* 323 | // ** The callback function for db_query 324 | // */ 325 | func _db_query_callback(tls *crt.TLS, _pUser unsafe.Pointer, _nArg int32, _azArg **int8, _NotUsed **int8) (r0 int32) { 326 | var _i int32 327 | var _pResult *TQueryResult 328 | _pResult = (*TQueryResult)(_pUser) 329 | if (_pResult.XnElem + _nArg) < _pResult.XnAlloc { 330 | goto _0 331 | } 332 | if _pResult.XnAlloc == int32(0) { 333 | _pResult.XnAlloc = _nArg + int32(1) 334 | goto _2 335 | } 336 | _pResult.XnAlloc = ((_pResult.XnAlloc * int32(2)) + _nArg) + int32(1) 337 | _2: 338 | _pResult.XazElem = (**int8)(crt.Xrealloc(tls, unsafe.Pointer(_pResult.XazElem), uint64(_pResult.XnAlloc)*uint64(8))) 339 | if _pResult.XazElem == nil { 340 | crt.Xfprintf(tls, (*crt.XFILE)(Xstdout), str(426), unsafe.Pointer(_pResult.XzFile)) 341 | return int32(1) 342 | } 343 | _0: 344 | if _azArg == nil { 345 | return int32(0) 346 | } 347 | _i = int32(0) 348 | _5: 349 | if _i >= _nArg { 350 | goto _8 351 | } 352 | *elem0(_pResult.XazElem, uintptr(postInc1(&_pResult.XnElem, 1))) = bin.Xsqlite3_mprintf(tls, str(445), unsafe.Pointer(func() *int8 { 353 | if (*elem0(_azArg, uintptr(_i))) != nil { 354 | return (*elem0(_azArg, uintptr(_i))) 355 | } 356 | return str(448) 357 | }())) 358 | _i += 1 359 | goto _5 360 | _8: 361 | return int32(0) 362 | } 363 | 364 | // C comment 365 | // /* 366 | // ** Check results 367 | // */ 368 | func Xdb_check(tls *crt.TLS, _zFile *int8, _zMsg *int8, _az **int8, args ...interface{}) { 369 | var _i int32 370 | var _z *int8 371 | var _ap []interface{} 372 | _ap = args 373 | _i = int32(0) 374 | _0: 375 | if store2(&_z, (*int8)(crt.VAPointer(&_ap))) == nil { 376 | goto _3 377 | } 378 | if ((*elem0(_az, uintptr(_i))) == nil) || (crt.Xstrcmp(tls, *elem0(_az, uintptr(_i)), _z) != int32(0)) { 379 | crt.Xfprintf(tls, (*crt.XFILE)(Xstdout), str(449), unsafe.Pointer(_zFile), unsafe.Pointer(_zMsg), _i+int32(1), unsafe.Pointer(*elem0(_az, uintptr(_i)))) 380 | Xdb_query_free(tls, _az) 381 | _Exit(tls, int32(1)) 382 | } 383 | _i += 1 384 | goto _0 385 | _3: 386 | _ap = nil 387 | Xdb_query_free(tls, _az) 388 | } 389 | 390 | // C comment 391 | // /* 392 | // ** Free the results of a db_query() call. 393 | // */ 394 | func Xdb_query_free(tls *crt.TLS, _az **int8) { 395 | var _i int32 396 | _i = int32(0) 397 | _0: 398 | if (*elem0(_az, uintptr(_i))) == nil { 399 | goto _3 400 | } 401 | bin.Xsqlite3_free(tls, unsafe.Pointer(*elem0(_az, uintptr(_i)))) 402 | _i += 1 403 | goto _0 404 | _3: 405 | crt.Xfree(tls, unsafe.Pointer(_az)) 406 | } 407 | 408 | var Xsig crt.Xpthread_cond_t 409 | 410 | func bool2int(b bool) int32 { 411 | if b { 412 | return 1 413 | } 414 | return 0 415 | } 416 | func bug20530(interface{}) {} //TODO remove when https://github.com/golang/go/issues/20530 is fixed. 417 | func init() { nzf32 *= -1; nzf64 *= -1 } 418 | 419 | var inf = math.Inf(1) 420 | var nzf32 float32 // -0.0 421 | var nzf64 float64 // -0.0 422 | func elem0(a **int8, index uintptr) **int8 { 423 | return (**int8)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 8*index)) 424 | } 425 | func elem2(a *int8, index uintptr) *int8 { 426 | return (*int8)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 1*index)) 427 | } 428 | func postInc1(p *int32, d int32) int32 { v := *p; *p += d; return v } 429 | func store2(p **int8, v *int8) *int8 { *p = v; return v } 430 | func store1(p *int32, v int32) int32 { *p = v; return v } 431 | 432 | type TQueryResult struct { 433 | XzFile *int8 434 | XnElem int32 435 | XnAlloc int32 436 | XazElem **int8 437 | } // t3 struct{zFile *int8,nElem int32,nAlloc int32,azElem **int8} 438 | func str(n int) *int8 { return (*int8)(unsafe.Pointer(&strTab[n])) } 439 | func wstr(n int) *int32 { return (*int32)(unsafe.Pointer(&strTab[n])) } 440 | 441 | var strTab = []byte("-v\x00testdb-%d\x00%d.testdb-%d\x00%s-journal\x00%s: START\x0a\x00%s: can't open\x0a\x00CREATE TABLE t%d(a,b,c);\x00INSERT INTO t%d VALUES(%d,%d,%d);\x00SELECT count(*) FROM t%d\x00tX size\x00100\x00SELECT avg(b) FROM t%d\x00tX avg\x00101.0\x00DELETE FROM t%d WHERE a>50\x00tX avg2\x0051.0\x00SELECT b, c FROM t%d WHERE a=%d\x00%d\x00readback\x00DROP TABLE t%d;\x00%s: END\x0a\x00BUSY %s #%d\x0a\x00EXEC %s: %s\x0a\x00DONE %s: %s\x0a\x00%s: command failed: %s - %s\x0a\x00QUERY %s: %s\x0a\x00DONE %s %s\x0a\x00%s: query failed: %s - %s\x0a\x00%s: malloc failed\x0a\x00%s\x00\x00%s: %s: bad result in column %d: %s\x0a\x00") 442 | -------------------------------------------------------------------------------- /internal/sqlite.org/sqlite-src-3190300/test/threadtest4.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** 2014-12-11 3 | ** 4 | ** The author disclaims copyright to this source code. In place of 5 | ** a legal notice, here is a blessing: 6 | ** 7 | ** May you do good and not evil. 8 | ** May you find forgiveness for yourself and forgive others. 9 | ** May you share freely, never taking more than you give. 10 | ** 11 | ************************************************************************* 12 | ** This file implements a simple standalone program used to stress the 13 | ** SQLite library when accessing the same set of databases simultaneously 14 | ** from multiple threads in shared-cache mode. 15 | ** 16 | ** This test program runs on unix-like systems only. It uses pthreads. 17 | ** To compile: 18 | ** 19 | ** gcc -g -Wall -I. threadtest4.c sqlite3.c -ldl -lpthread 20 | ** 21 | ** To run: 22 | ** 23 | ** ./a.out 10 24 | ** 25 | ** The argument is the number of threads. There are also options, such 26 | ** as -wal and -multithread and -serialized. 27 | ** 28 | ** Consider also compiling with clang instead of gcc and adding the 29 | ** -fsanitize=thread option. 30 | */ 31 | #include "sqlite3.h" 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | /* 41 | ** An instance of the following structure is passed into each worker 42 | ** thread. 43 | */ 44 | typedef struct WorkerInfo WorkerInfo; 45 | struct WorkerInfo { 46 | int tid; /* Thread ID */ 47 | int nWorker; /* Total number of workers */ 48 | unsigned wkrFlags; /* Flags */ 49 | sqlite3 *mainDb; /* Database connection of the main thread */ 50 | sqlite3 *db; /* Database connection of this thread */ 51 | int nErr; /* Number of errors seen by this thread */ 52 | int nTest; /* Number of tests run by this thread */ 53 | char *zMsg; /* Message returned by this thread */ 54 | pthread_t id; /* Thread id */ 55 | pthread_mutex_t *pWrMutex; /* Hold this mutex while writing */ 56 | }; 57 | 58 | /* 59 | ** Allowed values for WorkerInfo.wkrFlags 60 | */ 61 | #define TT4_SERIALIZED 0x0000001 /* The --serialized option is used */ 62 | #define TT4_WAL 0x0000002 /* WAL mode in use */ 63 | #define TT4_TRACE 0x0000004 /* Trace activity */ 64 | 65 | 66 | /* 67 | ** Report an OOM error and die if the argument is NULL 68 | */ 69 | static void check_oom(void *x){ 70 | if( x==0 ){ 71 | fprintf(stderr, "out of memory\n"); 72 | exit(1); 73 | } 74 | } 75 | 76 | /* 77 | ** Allocate memory. If the allocation fails, print an error message and 78 | ** kill the process. 79 | */ 80 | static void *safe_malloc(int sz){ 81 | void *x = sqlite3_malloc(sz>0?sz:1); 82 | check_oom(x); 83 | return x; 84 | } 85 | 86 | /* 87 | ** Print a trace message for a worker 88 | */ 89 | static void worker_trace(WorkerInfo *p, const char *zFormat, ...){ 90 | va_list ap; 91 | char *zMsg; 92 | if( (p->wkrFlags & TT4_TRACE)==0 ) return; 93 | va_start(ap, zFormat); 94 | zMsg = sqlite3_vmprintf(zFormat, ap); 95 | check_oom(zMsg); 96 | va_end(ap); 97 | fprintf(stderr, "TRACE(%02d): %s\n", p->tid, zMsg); 98 | sqlite3_free(zMsg); 99 | } 100 | 101 | /* 102 | ** Prepare a single SQL query 103 | */ 104 | static sqlite3_stmt *prep_sql(sqlite3 *db, const char *zFormat, ...){ 105 | va_list ap; 106 | char *zSql; 107 | int rc, i; 108 | sqlite3_stmt *pStmt = 0; 109 | 110 | va_start(ap, zFormat); 111 | zSql = sqlite3_vmprintf(zFormat, ap); 112 | va_end(ap); 113 | check_oom(zSql); 114 | for (i = 0; i < 1000; i++) { 115 | rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); 116 | if (rc == SQLITE_OK) { 117 | break; 118 | } 119 | } 120 | if( rc!=SQLITE_OK ){ 121 | fprintf(stderr, "SQL error (%d,%d): %s\nWhile preparing: [%s]\n", 122 | rc, sqlite3_extended_errcode(db), sqlite3_errmsg(db), zSql); 123 | exit(1); 124 | } 125 | sqlite3_free(zSql); 126 | return pStmt; 127 | } 128 | 129 | /* 130 | ** Run a SQL statements. Panic if unable. 131 | */ 132 | static void run_sql(WorkerInfo *p, const char *zFormat, ...){ 133 | va_list ap; 134 | char *zSql; 135 | int rc, i; 136 | sqlite3_stmt *pStmt = 0; 137 | int nRetry = 0; 138 | 139 | va_start(ap, zFormat); 140 | zSql = sqlite3_vmprintf(zFormat, ap); 141 | va_end(ap); 142 | check_oom(zSql); 143 | for (i = 0; i < 1000; i++) { 144 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); 145 | if (rc == SQLITE_OK) { 146 | break; 147 | } 148 | } 149 | if( rc!=SQLITE_OK ){ 150 | fprintf(stderr, "SQL error (%d,%d): %s\nWhile preparing: [%s]\n", 151 | rc, sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zSql); 152 | exit(1); 153 | } 154 | worker_trace(p, "running [%s]", zSql); 155 | while( (rc = sqlite3_step(pStmt))!=SQLITE_DONE ){ 156 | if( (rc&0xff)==SQLITE_BUSY || (rc&0xff)==SQLITE_LOCKED ){ 157 | sqlite3_reset(pStmt); 158 | nRetry++; 159 | if( nRetry<10 ){ 160 | worker_trace(p, "retry %d for [%s]", nRetry, zSql); 161 | sched_yield(); 162 | continue; 163 | }else{ 164 | fprintf(stderr, "Deadlock in thread %d while running [%s]\n", 165 | p->tid, zSql); 166 | exit(1); 167 | } 168 | } 169 | if( rc!=SQLITE_ROW ){ 170 | fprintf(stderr, "SQL error (%d,%d): %s\nWhile running [%s]\n", 171 | rc, sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zSql); 172 | exit(1); 173 | } 174 | } 175 | sqlite3_free(zSql); 176 | sqlite3_finalize(pStmt); 177 | } 178 | 179 | 180 | /* 181 | ** Open the database connection for WorkerInfo. The order in which 182 | ** the files are opened is a function of the tid value. 183 | */ 184 | static void worker_open_connection(WorkerInfo *p, int iCnt){ 185 | char *zFile; 186 | int x; 187 | int rc; 188 | static const unsigned char aOrder[6][3] = { 189 | { 1, 2, 3}, 190 | { 1, 3, 2}, 191 | { 2, 1, 3}, 192 | { 2, 3, 1}, 193 | { 3, 1, 2}, 194 | { 3, 2, 1} 195 | }; 196 | x = (p->tid + iCnt) % 6; 197 | zFile = sqlite3_mprintf("tt4-test%d.db", aOrder[x][0]); 198 | check_oom(zFile); 199 | worker_trace(p, "open %s", zFile); 200 | rc = sqlite3_open_v2(zFile, &p->db, 201 | SQLITE_OPEN_READWRITE|SQLITE_OPEN_SHAREDCACHE, 0); 202 | if( rc!=SQLITE_OK ){ 203 | fprintf(stderr, "sqlite_open_v2(%s) failed on thread %d\n", 204 | zFile, p->tid); 205 | exit(1); 206 | } 207 | sqlite3_free(zFile); 208 | run_sql(p, "PRAGMA read_uncommitted=ON;"); 209 | sqlite3_busy_timeout(p->db, 10000); 210 | run_sql(p, "PRAGMA synchronous=OFF;"); 211 | run_sql(p, "ATTACH 'tt4-test%d.db' AS aux1", aOrder[x][1]); 212 | run_sql(p, "ATTACH 'tt4-test%d.db' AS aux2", aOrder[x][2]); 213 | } 214 | 215 | /* 216 | ** Close the worker database connection 217 | */ 218 | static void worker_close_connection(WorkerInfo *p){ 219 | if( p->db ){ 220 | worker_trace(p, "close"); 221 | sqlite3_close(p->db); 222 | p->db = 0; 223 | } 224 | } 225 | 226 | /* 227 | ** Delete all content in the three databases associated with a 228 | ** single thread. Make this happen all in a single transaction if 229 | ** inTrans is true, or separately for each database if inTrans is 230 | ** false. 231 | */ 232 | static void worker_delete_all_content(WorkerInfo *p, int inTrans){ 233 | if( inTrans ){ 234 | pthread_mutex_lock(p->pWrMutex); 235 | run_sql(p, "BEGIN"); 236 | run_sql(p, "DELETE FROM t1 WHERE tid=%d", p->tid); 237 | run_sql(p, "DELETE FROM t2 WHERE tid=%d", p->tid); 238 | run_sql(p, "DELETE FROM t3 WHERE tid=%d", p->tid); 239 | run_sql(p, "COMMIT"); 240 | pthread_mutex_unlock(p->pWrMutex); 241 | p->nTest++; 242 | }else{ 243 | pthread_mutex_lock(p->pWrMutex); 244 | run_sql(p, "DELETE FROM t1 WHERE tid=%d", p->tid); 245 | pthread_mutex_unlock(p->pWrMutex); 246 | p->nTest++; 247 | pthread_mutex_lock(p->pWrMutex); 248 | run_sql(p, "DELETE FROM t2 WHERE tid=%d", p->tid); 249 | pthread_mutex_unlock(p->pWrMutex); 250 | p->nTest++; 251 | pthread_mutex_lock(p->pWrMutex); 252 | run_sql(p, "DELETE FROM t3 WHERE tid=%d", p->tid); 253 | pthread_mutex_unlock(p->pWrMutex); 254 | p->nTest++; 255 | } 256 | } 257 | 258 | /* 259 | ** Create rows mn through mx in table iTab for the given worker 260 | */ 261 | static void worker_add_content(WorkerInfo *p, int mn, int mx, int iTab){ 262 | char *zTabDef; 263 | switch( iTab ){ 264 | case 1: zTabDef = "t1(tid,sp,a,b,c)"; break; 265 | case 2: zTabDef = "t2(tid,sp,d,e,f)"; break; 266 | case 3: zTabDef = "t3(tid,sp,x,y,z)"; break; 267 | } 268 | pthread_mutex_lock(p->pWrMutex); 269 | run_sql(p, 270 | "WITH RECURSIVE\n" 271 | " c(i) AS (VALUES(%d) UNION ALL SELECT i+1 FROM c WHERE i<%d)\n" 272 | "INSERT INTO %s SELECT %d, zeroblob(3000), i, printf('%%d',i), i FROM c;", 273 | mn, mx, zTabDef, p->tid 274 | ); 275 | pthread_mutex_unlock(p->pWrMutex); 276 | p->nTest++; 277 | } 278 | 279 | /* 280 | ** Set an error message on a worker 281 | */ 282 | static void worker_error(WorkerInfo *p, const char *zFormat, ...){ 283 | va_list ap; 284 | p->nErr++; 285 | sqlite3_free(p->zMsg); 286 | va_start(ap, zFormat); 287 | p->zMsg = sqlite3_vmprintf(zFormat, ap); 288 | va_end(ap); 289 | } 290 | 291 | /* 292 | ** Each thread runs the following function. 293 | */ 294 | static void *worker_thread(void *pArg){ 295 | WorkerInfo *p = (WorkerInfo*)pArg; 296 | int iOuter; 297 | int i; 298 | int rc; 299 | sqlite3_stmt *pStmt; 300 | 301 | printf("worker %d startup\n", p->tid); fflush(stdout); 302 | for(iOuter=1; iOuter<=p->nWorker; iOuter++){ 303 | worker_open_connection(p, iOuter); 304 | for(i=0; i<4; i++){ 305 | worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter)%3 + 1); 306 | worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter+1)%3 + 1); 307 | worker_add_content(p, i*100+1, (i+1)*100, (p->tid+iOuter+2)%3 + 1); 308 | } 309 | 310 | pStmt = prep_sql(p->db, "SELECT count(a) FROM t1 WHERE tid=%d", p->tid); 311 | worker_trace(p, "query [%s]", sqlite3_sql(pStmt)); 312 | rc = sqlite3_step(pStmt); 313 | if( rc!=SQLITE_ROW ){ 314 | worker_error(p, "Failed to step: %s", sqlite3_sql(pStmt)); 315 | }else if( sqlite3_column_int(pStmt, 0)!=400 ){ 316 | worker_error(p, "Wrong result: %d", sqlite3_column_int(pStmt,0)); 317 | } 318 | sqlite3_finalize(pStmt); 319 | if( p->nErr ) break; 320 | 321 | if( ((iOuter+p->tid)%3)==0 ){ 322 | sqlite3_db_release_memory(p->db); 323 | p->nTest++; 324 | } 325 | 326 | pthread_mutex_lock(p->pWrMutex); 327 | run_sql(p, "BEGIN;"); 328 | run_sql(p, "UPDATE t1 SET c=NULL WHERE a=55"); 329 | run_sql(p, "UPDATE t2 SET f=NULL WHERE d=42"); 330 | run_sql(p, "UPDATE t3 SET z=NULL WHERE x=31"); 331 | run_sql(p, "ROLLBACK;"); 332 | p->nTest++; 333 | pthread_mutex_unlock(p->pWrMutex); 334 | 335 | 336 | if( iOuter==p->tid ){ 337 | pthread_mutex_lock(p->pWrMutex); 338 | run_sql(p, "VACUUM"); 339 | pthread_mutex_unlock(p->pWrMutex); 340 | } 341 | 342 | pStmt = prep_sql(p->db, 343 | "SELECT t1.rowid, t2.rowid, t3.rowid" 344 | " FROM t1, t2, t3" 345 | " WHERE t1.tid=%d AND t2.tid=%d AND t3.tid=%d" 346 | " AND t1.a<>t2.d AND t2.d<>t3.x" 347 | " ORDER BY 1, 2, 3" 348 | ,p->tid, p->tid, p->tid); 349 | worker_trace(p, "query [%s]", sqlite3_sql(pStmt)); 350 | for(i=0; inWorker; i++){ 351 | rc = sqlite3_step(pStmt); 352 | if( rc!=SQLITE_ROW ){ 353 | worker_error(p, "Failed to step: %s", sqlite3_sql(pStmt)); 354 | break; 355 | } 356 | sched_yield(); 357 | } 358 | sqlite3_finalize(pStmt); 359 | if( p->nErr ) break; 360 | 361 | worker_delete_all_content(p, (p->tid+iOuter)%2); 362 | worker_close_connection(p); 363 | p->db = 0; 364 | } 365 | worker_close_connection(p); 366 | printf("worker %d finished\n", p->tid); fflush(stdout); 367 | return 0; 368 | } 369 | 370 | int main(int argc, char **argv){ 371 | int nWorker = 0; /* Number of worker threads */ 372 | int i; /* Loop counter */ 373 | WorkerInfo *aInfo; /* Information for each worker */ 374 | unsigned wkrFlags = 0; /* Default worker flags */ 375 | int nErr = 0; /* Number of errors */ 376 | int nTest = 0; /* Number of tests */ 377 | int rc; /* Return code */ 378 | sqlite3 *db = 0; /* Main database connection */ 379 | pthread_mutex_t wrMutex; /* The write serialization mutex */ 380 | WorkerInfo infoTop; /* WorkerInfo for the main thread */ 381 | WorkerInfo *p; /* Pointer to infoTop */ 382 | 383 | sqlite3_config(SQLITE_CONFIG_MULTITHREAD); 384 | for(i=1; i='1' && z[0]<='9' && nWorker==0 ){ 403 | nWorker = atoi(z); 404 | if( nWorker<2 ){ 405 | fprintf(stderr, "minimum of 2 threads\n"); 406 | exit(1); 407 | } 408 | }else{ 409 | fprintf(stderr, "extra command-line argument: \"%s\"\n", argv[i]); 410 | exit(1); 411 | } 412 | } 413 | if( nWorker==0 ){ 414 | fprintf(stderr, 415 | "usage: %s ?OPTIONS? N\n" 416 | "N is the number of threads and must be at least 2.\n" 417 | "Options:\n" 418 | " --serialized\n" 419 | " --multithread\n" 420 | " --wal\n" 421 | " --trace\n" 422 | ,argv[0] 423 | ); 424 | exit(1); 425 | } 426 | if( !sqlite3_threadsafe() ){ 427 | fprintf(stderr, "requires a threadsafe build of SQLite\n"); 428 | exit(1); 429 | } 430 | sqlite3_initialize(); 431 | sqlite3_enable_shared_cache(1); 432 | pthread_mutex_init(&wrMutex, 0); 433 | 434 | /* Initialize the test database files */ 435 | (void)unlink("tt4-test1.db"); 436 | (void)unlink("tt4-test2.db"); 437 | (void)unlink("tt4-test3.db"); 438 | rc = sqlite3_open("tt4-test1.db", &db); 439 | if( rc!=SQLITE_OK ){ 440 | fprintf(stderr, "Unable to open test database: tt4-test2.db\n"); 441 | exit(1); 442 | } 443 | memset(&infoTop, 0, sizeof(infoTop)); 444 | infoTop.db = db; 445 | infoTop.wkrFlags = wkrFlags; 446 | p = &infoTop; 447 | if( wkrFlags & TT4_WAL ){ 448 | run_sql(p, "PRAGMA journal_mode=WAL"); 449 | } 450 | run_sql(p, "PRAGMA synchronous=OFF"); 451 | run_sql(p, "CREATE TABLE IF NOT EXISTS t1(tid INTEGER, sp, a, b, c)"); 452 | run_sql(p, "CREATE INDEX t1tid ON t1(tid)"); 453 | run_sql(p, "CREATE INDEX t1ab ON t1(a,b)"); 454 | run_sql(p, "ATTACH 'tt4-test2.db' AS 'test2'"); 455 | run_sql(p, "CREATE TABLE IF NOT EXISTS test2.t2(tid INTEGER, sp, d, e, f)"); 456 | run_sql(p, "CREATE INDEX test2.t2tid ON t2(tid)"); 457 | run_sql(p, "CREATE INDEX test2.t2de ON t2(d,e)"); 458 | run_sql(p, "ATTACH 'tt4-test3.db' AS 'test3'"); 459 | run_sql(p, "CREATE TABLE IF NOT EXISTS test3.t3(tid INTEGER, sp, x, y, z)"); 460 | run_sql(p, "CREATE INDEX test3.t3tid ON t3(tid)"); 461 | run_sql(p, "CREATE INDEX test3.t3xy ON t3(x,y)"); 462 | aInfo = safe_malloc( sizeof(*aInfo)*nWorker ); 463 | memset(aInfo, 0, sizeof(*aInfo)*nWorker); 464 | for(i=0; i 208 | %s 209 | `, ndbg, runtime.GOARCH, runtime.GOOS, predef), 210 | src, 211 | model, 212 | append([]cc.Opt{ 213 | cc.AllowCompatibleTypedefRedefinitions(), 214 | cc.EnableEmptyStructs(), 215 | cc.EnableImplicitFuncDef(), 216 | cc.EnableNonConstStaticInitExpressions(), 217 | cc.EnableWideBitFieldTypes(), 218 | cc.ErrLimit(*errLimit), 219 | cc.KeepComments(), 220 | cc.SysIncludePaths([]string{ccir.LibcIncludePath}), 221 | }, opts...)..., 222 | ) 223 | if err != nil { 224 | log.Fatal(errStr(err)) 225 | } 226 | 227 | build = append(build, ast) 228 | } 229 | 230 | var out buffer.Bytes 231 | if err := ccgo.New(build, &out, ccgoOpts...); err != nil { 232 | log.Fatal(err) 233 | } 234 | 235 | return build, out.Bytes() 236 | } 237 | 238 | func macros(buf io.Writer, ast *cc.TranslationUnit) { 239 | fmt.Fprintf(buf, `const ( 240 | `) 241 | var a []string 242 | for k, v := range ast.Macros { 243 | if v.Value != nil && v.Type.Kind() != cc.Bool { 244 | switch fn := v.DefTok.Position().Filename; { 245 | case 246 | fn == "builtin.h", 247 | fn == "", 248 | strings.HasPrefix(fn, "predefined_"): 249 | // ignore 250 | default: 251 | a = append(a, string(dict.S(k))) 252 | } 253 | } 254 | } 255 | sort.Strings(a) 256 | for _, v := range a { 257 | m := ast.Macros[dict.SID(v)] 258 | if m.Value == nil { 259 | log.Fatal("TODO") 260 | } 261 | 262 | switch t := m.Type; t.Kind() { 263 | case 264 | cc.Int, cc.UInt, cc.Long, cc.ULong, cc.LongLong, cc.ULongLong, 265 | cc.Float, cc.Double, cc.LongDouble, cc.Bool: 266 | fmt.Fprintf(buf, "X%s = %v\n", v, m.Value) 267 | case cc.Ptr: 268 | switch t := t.Element(); t.Kind() { 269 | case cc.Char: 270 | fmt.Fprintf(buf, "X%s = %q\n", v, dict.S(int(m.Value.(cc.StringLitID)))) 271 | default: 272 | log.Fatalf("%v", t.Kind()) 273 | } 274 | default: 275 | log.Fatalf("%v", t.Kind()) 276 | } 277 | } 278 | 279 | a = a[:0] 280 | for _, v := range ast.Declarations.Identifiers { 281 | switch x := v.Node.(type) { 282 | case *cc.DirectDeclarator: 283 | d := x.TopDeclarator() 284 | id, _ := d.Identifier() 285 | if x.EnumVal == nil { 286 | break 287 | } 288 | 289 | a = append(a, string(dict.S(id))) 290 | default: 291 | log.Fatalf("%T", x) 292 | } 293 | } 294 | sort.Strings(a) 295 | for _, v := range a { 296 | dd := ast.Declarations.Identifiers[dict.SID(v)].Node.(*cc.DirectDeclarator) 297 | fmt.Fprintf(buf, "X%s = %v\n", v, dd.EnumVal) 298 | } 299 | fmt.Fprintf(buf, ")\n") 300 | } 301 | 302 | func unconvert(pth string) { 303 | wd, err := os.Getwd() 304 | if err != nil { 305 | log.Fatal(err) 306 | } 307 | 308 | defer func() { 309 | if err := os.Chdir(wd); err != nil { 310 | log.Fatal(err) 311 | } 312 | }() 313 | 314 | if err := os.Chdir(filepath.Dir(pth)); err != nil { 315 | log.Fatal(err) 316 | } 317 | 318 | if out, err := exec.Command(unconvertBin, "-apply").CombinedOutput(); err != nil { 319 | log.Fatalf("unconvert: %s\n%s", err, out) 320 | } 321 | } 322 | 323 | func cp(dst, src, glob string) { 324 | pat := filepath.Join(filepath.FromSlash(src), glob) 325 | m, err := filepath.Glob(pat) 326 | if err != nil { 327 | log.Fatal(err) 328 | } 329 | 330 | if len(m) == 0 { 331 | log.Fatalf("cp(%q, %q, %q): no files for %q", dst, src, glob, pat) 332 | } 333 | 334 | dst = filepath.FromSlash(dst) 335 | for _, v := range m { 336 | f, err := ioutil.ReadFile(v) 337 | if err != nil { 338 | log.Fatal(err) 339 | } 340 | 341 | _, nm := filepath.Split(v) 342 | if err := ioutil.WriteFile(filepath.Join(dst, nm), f, 0664); err != nil { 343 | log.Fatal(err) 344 | } 345 | } 346 | } 347 | 348 | func header(f string) []byte { 349 | b, err := ioutil.ReadFile(f) 350 | if err != nil { 351 | log.Fatal(err) 352 | } 353 | 354 | var s scanner.Scanner 355 | s.Init(token.NewFileSet().AddFile(f, -1, len(b)), b, nil, scanner.ScanComments) 356 | var buf buffer.Bytes 357 | for { 358 | _, tok, lit := s.Scan() 359 | switch tok { 360 | case token.COMMENT: 361 | buf.WriteString(lit) 362 | buf.WriteByte('\n') 363 | default: 364 | return buf.Bytes() 365 | } 366 | } 367 | } 368 | 369 | func tidyComment(s string) string { 370 | switch { 371 | case strings.HasPrefix(s, "/*"): 372 | a := strings.Split("/"+s[1:len(s)-1], "\n") 373 | for i, v := range a { 374 | a[i] = "// " + v 375 | } 376 | return strings.Join(a, "\n") + "/\n" 377 | case strings.HasPrefix(s, "//"): 378 | return "// " + s[2:] + "\n" 379 | default: 380 | panic("internal error") 381 | } 382 | } 383 | 384 | func tidyComments(b []byte) string { 385 | var s scanner.Scanner 386 | s.Init(token.NewFileSet().AddFile("", -1, len(b)), b, nil, scanner.ScanComments) 387 | var a []string 388 | for { 389 | _, tok, lit := s.Scan() 390 | if tok == token.EOF { 391 | return strings.Join(a, "\n") 392 | } 393 | 394 | a = append(a, tidyComment(lit)) 395 | } 396 | } 397 | 398 | func sqlite() { 399 | repo := findRepo(sqliteRepo) 400 | if repo == "" { 401 | log.Fatalf("repository not found: %v", sqliteRepo) 402 | return 403 | } 404 | 405 | pth := filepath.Join(repo, "sqlite-amalgamation-"+version) 406 | ast, _ := build( 407 | defines, 408 | [][]string{ 409 | {filepath.Join(pth, "sqlite3.h")}, 410 | {"main.c"}, 411 | }, 412 | []ccgo.Option{ccgo.Library(), ccgo.LibcTypes()}, 413 | cc.EnableAnonymousStructFields(), 414 | cc.IncludePaths([]string{pth}), 415 | ) 416 | sqlite3 := filepath.Join(pth, "sqlite3.c") 417 | _, src := build( 418 | defines, 419 | [][]string{ 420 | {sqlite3}, 421 | {"main.c"}, 422 | }, 423 | []ccgo.Option{ccgo.Library(), ccgo.LibcTypes()}, 424 | cc.EnableAnonymousStructFields(), 425 | cc.IncludePaths([]string{pth}), 426 | ) 427 | 428 | var b bytes.Buffer 429 | lic, err := ioutil.ReadFile("SQLITE-LICENSE") 430 | if err != nil { 431 | log.Fatal(err) 432 | } 433 | 434 | fmt.Fprintf(&b, prologueSqlite, lic, strings.TrimSpace(tidyComments(header(sqlite3)))) 435 | macros(&b, ast[0]) 436 | b.Write(src) 437 | b2, err := format.Source(b.Bytes()) 438 | if err != nil { 439 | b2 = b.Bytes() 440 | } 441 | if err := os.MkdirAll(filepath.Join("internal", "bin"), 0775); err != nil { 442 | log.Fatal(err) 443 | } 444 | 445 | dst := fmt.Sprintf(filepath.Join("internal", "bin", "bin_%s_%s.go"), runtime.GOOS, runtime.GOARCH) 446 | b2 = bytes.Replace(b2, []byte("var Xsqlite3PendingByte int32"), []byte("func Xsqlite3PendingByte() int32 { return _sqlite3PendingByte }"), 1) 447 | if err := ioutil.WriteFile(dst, b2, 0664); err != nil { 448 | log.Fatal(err) 449 | } 450 | 451 | unconvert(dst) 452 | } 453 | 454 | func mpTest() { 455 | repo := findRepo(sqliteRepo) 456 | if repo == "" { 457 | log.Fatalf("repository not found: %v", sqliteRepo) 458 | return 459 | } 460 | 461 | sqlitePth := filepath.Join(repo, "sqlite-amalgamation-"+version) 462 | pth := filepath.Join(repo, "sqlite-src-"+version, "mptest") 463 | tag := "mptest" 464 | test := filepath.Join(pth, tag+".c") 465 | _, src := build( 466 | defines, 467 | [][]string{ 468 | {filepath.Join(sqlitePth, "sqlite3.c")}, 469 | {test}, 470 | }, 471 | []ccgo.Option{ccgo.Packages([]string{"bin"}), ccgo.LibcTypes()}, 472 | cc.EnableAnonymousStructFields(), 473 | cc.IncludePaths([]string{sqlitePth}), 474 | ) 475 | 476 | var b bytes.Buffer 477 | fmt.Fprintf(&b, prologueTest, tag, strings.TrimSpace(tidyComments(header(test)))) 478 | b.Write(src) 479 | b2, err := format.Source(b.Bytes()) 480 | if err != nil { 481 | b2 = b.Bytes() 482 | } 483 | if err := os.MkdirAll(filepath.Join("internal", tag), 0775); err != nil { 484 | log.Fatal(err) 485 | } 486 | 487 | if err := os.MkdirAll(filepath.Join("testdata", tag), 0775); err != nil { 488 | log.Fatal(err) 489 | } 490 | 491 | dst := fmt.Sprintf(filepath.Join("internal", tag, tag+"_%s_%s.go"), runtime.GOOS, runtime.GOARCH) 492 | if err := ioutil.WriteFile(dst, b2, 0664); err != nil { 493 | log.Fatal(err) 494 | } 495 | 496 | unconvert(dst) 497 | cp(filepath.Join("testdata", tag), pth, "*.test") 498 | cp(filepath.Join("testdata", tag), pth, "*.subtest") 499 | } 500 | 501 | func threadTest1() { 502 | repo := findRepo(sqliteRepo) 503 | if repo == "" { 504 | log.Fatalf("repository not found: %v", sqliteRepo) 505 | return 506 | } 507 | 508 | sqlitePth := filepath.Join(repo, "sqlite-amalgamation-"+version) 509 | tag := "threadtest1" 510 | test := filepath.Join("internal", "sqlite.org", "sqlite-src-3190300", "test", "threadtest1.c") 511 | _, src := build( 512 | defines, 513 | [][]string{ 514 | {filepath.Join(sqlitePth, "sqlite3.c")}, 515 | {test}, 516 | }, 517 | []ccgo.Option{ccgo.Packages([]string{"bin"}), ccgo.LibcTypes()}, 518 | cc.EnableAnonymousStructFields(), 519 | cc.IncludePaths([]string{".", sqlitePth, filepath.Join(repo, "sqlite-src-"+version, "src")}), 520 | ) 521 | 522 | var b bytes.Buffer 523 | fmt.Fprintf(&b, prologueTest, tag, strings.TrimSpace(tidyComments(header(test)))) 524 | b.Write(src) 525 | b2, err := format.Source(b.Bytes()) 526 | if err != nil { 527 | b2 = b.Bytes() 528 | } 529 | if err := os.MkdirAll(filepath.Join("internal", tag), 0775); err != nil { 530 | log.Fatal(err) 531 | } 532 | 533 | if err := os.MkdirAll(filepath.Join("testdata", tag), 0775); err != nil { 534 | log.Fatal(err) 535 | } 536 | 537 | dst := fmt.Sprintf(filepath.Join("internal", tag, tag+"_%s_%s.go"), runtime.GOOS, runtime.GOARCH) 538 | if err := ioutil.WriteFile(dst, b2, 0664); err != nil { 539 | log.Fatal(err) 540 | } 541 | 542 | unconvert(dst) 543 | } 544 | 545 | func threadTest2() { 546 | repo := findRepo(sqliteRepo) 547 | if repo == "" { 548 | log.Fatalf("repository not found: %v", sqliteRepo) 549 | return 550 | } 551 | 552 | sqlitePth := filepath.Join(repo, "sqlite-amalgamation-"+version) 553 | pth := filepath.Join(repo, "sqlite-src-"+version, "test") 554 | tag := "threadtest2" 555 | test := filepath.Join(pth, tag+".c") 556 | _, src := build( 557 | defines, 558 | [][]string{ 559 | {filepath.Join(sqlitePth, "sqlite3.c")}, 560 | {test}, 561 | }, 562 | []ccgo.Option{ccgo.Packages([]string{"bin"}), ccgo.LibcTypes()}, 563 | cc.EnableAnonymousStructFields(), 564 | cc.IncludePaths([]string{".", sqlitePth, filepath.Join(repo, "sqlite-src-"+version, "src")}), 565 | ) 566 | 567 | var b bytes.Buffer 568 | fmt.Fprintf(&b, prologueTest, tag, strings.TrimSpace(tidyComments(header(test)))) 569 | b.Write(src) 570 | b2, err := format.Source(b.Bytes()) 571 | if err != nil { 572 | b2 = b.Bytes() 573 | } 574 | if err := os.MkdirAll(filepath.Join("internal", tag), 0775); err != nil { 575 | log.Fatal(err) 576 | } 577 | 578 | if err := os.MkdirAll(filepath.Join("testdata", tag), 0775); err != nil { 579 | log.Fatal(err) 580 | } 581 | 582 | dst := fmt.Sprintf(filepath.Join("internal", tag, tag+"_%s_%s.go"), runtime.GOOS, runtime.GOARCH) 583 | if err := ioutil.WriteFile(dst, b2, 0664); err != nil { 584 | log.Fatal(err) 585 | } 586 | 587 | unconvert(dst) 588 | } 589 | 590 | func threadTest3() { 591 | n := 3 592 | repo := findRepo(sqliteRepo) 593 | if repo == "" { 594 | log.Fatalf("repository not found: %v", sqliteRepo) 595 | return 596 | } 597 | 598 | sqlitePth := filepath.Join(repo, "sqlite-amalgamation-"+version) 599 | pth := filepath.Join(repo, "sqlite-src-"+version, "test") 600 | tag := fmt.Sprintf("threadtest%v", n) 601 | test := filepath.Join(pth, tag+".c") 602 | _, src := build( 603 | defines, 604 | [][]string{ 605 | {filepath.Join(sqlitePth, "sqlite3.c")}, 606 | {filepath.Join(repo, "sqlite-src-"+version, "src", "test_multiplex.c")}, 607 | {test}, 608 | }, 609 | []ccgo.Option{ccgo.Packages([]string{"bin"}), ccgo.LibcTypes()}, 610 | cc.EnableAnonymousStructFields(), 611 | cc.IncludePaths([]string{".", sqlitePth, filepath.Join(repo, "sqlite-src-"+version, "src")}), 612 | ) 613 | 614 | var b bytes.Buffer 615 | fmt.Fprintf(&b, prologueTest, tag, strings.TrimSpace(tidyComments(header(test)))) 616 | b.Write(src) 617 | b2, err := format.Source(b.Bytes()) 618 | if err != nil { 619 | b2 = b.Bytes() 620 | } 621 | if err := os.MkdirAll(filepath.Join("internal", tag), 0775); err != nil { 622 | log.Fatal(err) 623 | } 624 | 625 | if err := os.MkdirAll(filepath.Join("testdata", tag), 0775); err != nil { 626 | log.Fatal(err) 627 | } 628 | 629 | dst := fmt.Sprintf(filepath.Join("internal", tag, tag+"_%s_%s.go"), runtime.GOOS, runtime.GOARCH) 630 | b2 = bytes.Replace(b2, []byte("Xsqlite3PendingByte"), []byte("bin.Xsqlite3PendingByte()"), -1) 631 | if err := ioutil.WriteFile(dst, b2, 0664); err != nil { 632 | log.Fatal(err) 633 | } 634 | 635 | unconvert(dst) 636 | } 637 | 638 | func threadTest4() { 639 | repo := findRepo(sqliteRepo) 640 | if repo == "" { 641 | log.Fatalf("repository not found: %v", sqliteRepo) 642 | return 643 | } 644 | 645 | sqlitePth := filepath.Join(repo, "sqlite-amalgamation-"+version) 646 | tag := "threadtest4" 647 | test := filepath.Join("internal", "sqlite.org", "sqlite-src-3190300", "test", "threadtest4.c") 648 | _, src := build( 649 | defines, 650 | [][]string{ 651 | {filepath.Join(sqlitePth, "sqlite3.c")}, 652 | {test}, 653 | }, 654 | []ccgo.Option{ccgo.Packages([]string{"bin"}), ccgo.LibcTypes()}, 655 | cc.EnableAnonymousStructFields(), 656 | cc.IncludePaths([]string{".", sqlitePth, filepath.Join(repo, "sqlite-src-"+version, "src")}), 657 | ) 658 | 659 | var b bytes.Buffer 660 | fmt.Fprintf(&b, prologueTest, tag, strings.TrimSpace(tidyComments(header(test)))) 661 | b.Write(src) 662 | b2, err := format.Source(b.Bytes()) 663 | if err != nil { 664 | b2 = b.Bytes() 665 | } 666 | if err := os.MkdirAll(filepath.Join("internal", tag), 0775); err != nil { 667 | log.Fatal(err) 668 | } 669 | 670 | if err := os.MkdirAll(filepath.Join("testdata", tag), 0775); err != nil { 671 | log.Fatal(err) 672 | } 673 | 674 | dst := fmt.Sprintf(filepath.Join("internal", tag, tag+"_%s_%s.go"), runtime.GOOS, runtime.GOARCH) 675 | if err := ioutil.WriteFile(dst, b2, 0664); err != nil { 676 | log.Fatal(err) 677 | } 678 | 679 | unconvert(dst) 680 | } 681 | 682 | func main() { 683 | log.SetFlags(log.Lshortfile | log.Lmicroseconds) 684 | var err error 685 | if unconvertBin, err = exec.LookPath("unconvert"); err != nil { 686 | log.Fatal("Please install the unconvert tool (go get -u github.com/mdempsky/unconvert)") 687 | } 688 | 689 | flag.Parse() 690 | 691 | sqlite() 692 | mpTest() 693 | threadTest1() 694 | threadTest2() 695 | threadTest3() 696 | threadTest4() 697 | } 698 | -------------------------------------------------------------------------------- /internal/threadtest4/threadtest4_linux_386.go: -------------------------------------------------------------------------------- 1 | // Code generated by ccgo. DO NOT EDIT. 2 | 3 | // threadtest4 4 | // /* 5 | // ** 2014-12-11 6 | // ** 7 | // ** The author disclaims copyright to this source code. In place of 8 | // ** a legal notice, here is a blessing: 9 | // ** 10 | // ** May you do good and not evil. 11 | // ** May you find forgiveness for yourself and forgive others. 12 | // ** May you share freely, never taking more than you give. 13 | // ** 14 | // ************************************************************************* 15 | // ** This file implements a simple standalone program used to stress the 16 | // ** SQLite library when accessing the same set of databases simultaneously 17 | // ** from multiple threads in shared-cache mode. 18 | // ** 19 | // ** This test program runs on unix-like systems only. It uses pthreads. 20 | // ** To compile: 21 | // ** 22 | // ** gcc -g -Wall -I. threadtest4.c sqlite3.c -ldl -lpthread 23 | // ** 24 | // ** To run: 25 | // ** 26 | // ** ./a.out 10 27 | // ** 28 | // ** The argument is the number of threads. There are also options, such 29 | // ** as -wal and -multithread and -serialized. 30 | // ** 31 | // ** Consider also compiling with clang instead of gcc and adding the 32 | // ** -fsanitize=thread option. 33 | // */ 34 | package main 35 | 36 | import ( 37 | "math" 38 | "os" 39 | "unsafe" 40 | 41 | "github.com/cznic/ccgo/crt" 42 | "github.com/cznic/sqlite/internal/bin" 43 | ) 44 | 45 | var argv []*int8 46 | 47 | func main() { 48 | for _, v := range os.Args { 49 | argv = append(argv, (*int8)(crt.CString(v))) 50 | } 51 | argv = append(argv, nil) 52 | X_start(crt.NewTLS(), int32(len(os.Args)), &argv[0]) 53 | } 54 | 55 | func X_start(tls *crt.TLS, _argc int32, _argv **int8) { 56 | crt.X__register_stdfiles(tls, Xstdin, Xstdout, Xstderr) 57 | crt.X__builtin_exit(tls, Xmain(tls, _argc, _argv)) 58 | } 59 | 60 | var Xstdin unsafe.Pointer 61 | 62 | func init() { 63 | Xstdin = unsafe.Pointer(&X__stdfiles) 64 | } 65 | 66 | var X__stdfiles [3]unsafe.Pointer 67 | 68 | var Xstdout unsafe.Pointer 69 | 70 | func init() { 71 | Xstdout = unsafe.Pointer(uintptr(unsafe.Pointer(&X__stdfiles)) + 4) 72 | } 73 | 74 | var Xstderr unsafe.Pointer 75 | 76 | func init() { 77 | Xstderr = unsafe.Pointer(uintptr(unsafe.Pointer(&X__stdfiles)) + 8) 78 | } 79 | 80 | func Xmain(tls *crt.TLS, _argc int32, _argv **int8) (r0 int32) { 81 | var _nWorker, _i, _nErr, _nTest, _rc int32 82 | var _wkrFlags uint32 83 | var _1_z *int8 84 | var _db unsafe.Pointer 85 | var _wrMutex crt.Xpthread_mutex_t 86 | var _infoTop XWorkerInfo 87 | var _aInfo, _p *XWorkerInfo 88 | r0 = int32(0) 89 | _nWorker = int32(0) 90 | _wkrFlags = uint32(0) 91 | _nErr = int32(0) 92 | _nTest = int32(0) 93 | _db = nil 94 | bin.Xsqlite3_config(tls, int32(2)) 95 | _i = int32(1) 96 | _0: 97 | if _i >= _argc { 98 | goto _3 99 | } 100 | _1_z = *elem0(_argv, uintptr(_i)) 101 | if int32(*elem1(_1_z, 0)) != int32(45) { 102 | goto _4 103 | } 104 | if (int32(*elem1(_1_z, uintptr(1))) == int32(45)) && (int32(*elem1(_1_z, uintptr(2))) != int32(0)) { 105 | *(*uintptr)(unsafe.Pointer(&_1_z)) += uintptr(1) 106 | } 107 | if crt.Xstrcmp(tls, _1_z, str(0)) == int32(0) { 108 | bin.Xsqlite3_config(tls, int32(2)) 109 | _wkrFlags &= uint32(4294967294) 110 | goto _14 111 | } 112 | if crt.Xstrcmp(tls, _1_z, str(13)) == int32(0) { 113 | bin.Xsqlite3_config(tls, int32(3)) 114 | _wkrFlags |= uint32(1) 115 | goto _14 116 | } 117 | if crt.Xstrcmp(tls, _1_z, str(25)) == int32(0) { 118 | _wkrFlags |= uint32(2) 119 | goto _14 120 | } 121 | if crt.Xstrcmp(tls, _1_z, str(30)) == int32(0) { 122 | _wkrFlags |= uint32(4) 123 | goto _14 124 | } 125 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(37), unsafe.Pointer(*elem0(_argv, uintptr(_i)))) 126 | crt.Xexit(tls, int32(1)) 127 | _14: 128 | goto _20 129 | _4: 130 | if int32(*elem1(_1_z, 0)) < int32(49) || int32(*elem1(_1_z, 0)) > int32(57) || _nWorker != int32(0) { 131 | goto _18 132 | } 133 | _nWorker = crt.Xatoi(tls, _1_z) 134 | if _nWorker < int32(2) { 135 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(70)) 136 | crt.Xexit(tls, int32(1)) 137 | } 138 | goto _20 139 | _18: 140 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(92), unsafe.Pointer(*elem0(_argv, uintptr(_i)))) 141 | crt.Xexit(tls, int32(1)) 142 | _20: 143 | _i += 1 144 | goto _0 145 | _3: 146 | if _nWorker == int32(0) { 147 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(127), unsafe.Pointer(*elem0(_argv, 0))) 148 | crt.Xexit(tls, int32(1)) 149 | } 150 | if bin.Xsqlite3_threadsafe(tls) == 0 { 151 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(260)) 152 | crt.Xexit(tls, int32(1)) 153 | } 154 | bin.Xsqlite3_initialize(tls) 155 | bin.Xsqlite3_enable_shared_cache(tls, int32(1)) 156 | crt.Xpthread_mutex_init(tls, &_wrMutex, nil) 157 | crt.Xunlink(tls, str(299)) 158 | crt.Xunlink(tls, str(312)) 159 | crt.Xunlink(tls, str(325)) 160 | _rc = bin.Xsqlite3_open(tls, str(299), (**bin.Xsqlite3)(unsafe.Pointer(&_db))) 161 | if _rc != int32(0) { 162 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(338)) 163 | crt.Xexit(tls, int32(1)) 164 | } 165 | crt.Xmemset(tls, unsafe.Pointer(&_infoTop), int32(0), uint32(40)) 166 | _infoTop.Xdb = _db 167 | _infoTop.XwkrFlags = _wkrFlags 168 | _p = &_infoTop 169 | if (_wkrFlags & uint32(2)) != 0 { 170 | _run_sql(tls, _p, str(382)) 171 | } 172 | _run_sql(tls, _p, str(406)) 173 | _run_sql(tls, _p, str(429)) 174 | _run_sql(tls, _p, str(485)) 175 | _run_sql(tls, _p, str(515)) 176 | _run_sql(tls, _p, str(544)) 177 | _run_sql(tls, _p, str(577)) 178 | _run_sql(tls, _p, str(639)) 179 | _run_sql(tls, _p, str(675)) 180 | _run_sql(tls, _p, str(710)) 181 | _run_sql(tls, _p, str(743)) 182 | _run_sql(tls, _p, str(805)) 183 | _run_sql(tls, _p, str(841)) 184 | _aInfo = (*XWorkerInfo)(_safe_malloc(tls, int32(uint32(40)*uint32(_nWorker)))) 185 | crt.Xmemset(tls, unsafe.Pointer(_aInfo), int32(0), uint32(40)*uint32(_nWorker)) 186 | _i = int32(0) 187 | _25: 188 | if _i >= _nWorker { 189 | goto _28 190 | } 191 | elem2(_aInfo, uintptr(_i)).Xtid = _i + int32(1) 192 | elem2(_aInfo, uintptr(_i)).XnWorker = _nWorker 193 | elem2(_aInfo, uintptr(_i)).XwkrFlags = _wkrFlags 194 | elem2(_aInfo, uintptr(_i)).XmainDb = _db 195 | *(**crt.Xpthread_mutex_t)(unsafe.Pointer(&(elem2(_aInfo, uintptr(_i)).XpWrMutex))) = &_wrMutex 196 | _rc = crt.Xpthread_create(tls, &(elem2(_aInfo, uintptr(_i)).Xid), nil, _worker_thread, unsafe.Pointer(elem2(_aInfo, uintptr(_i)))) 197 | if _rc != int32(0) { 198 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(876), _i+int32(1)) 199 | crt.Xexit(tls, int32(1)) 200 | } 201 | crt.Xsched_yield(tls) 202 | _i += 1 203 | goto _25 204 | _28: 205 | _i = int32(0) 206 | _30: 207 | if _i >= _nWorker { 208 | goto _33 209 | } 210 | crt.Xpthread_join(tls, elem2(_aInfo, uintptr(_i)).Xid, nil) 211 | crt.Xprintf(tls, str(914), elem2(_aInfo, uintptr(_i)).Xtid, elem2(_aInfo, uintptr(_i)).XnErr, elem2(_aInfo, uintptr(_i)).XnTest) 212 | if (elem2(_aInfo, uintptr(_i)).XzMsg) != nil { 213 | crt.Xprintf(tls, str(954), unsafe.Pointer(elem2(_aInfo, uintptr(_i)).XzMsg)) 214 | goto _35 215 | } 216 | crt.Xprintf(tls, str(960)) 217 | _35: 218 | _nErr += elem2(_aInfo, uintptr(_i)).XnErr 219 | _nTest += elem2(_aInfo, uintptr(_i)).XnTest 220 | crt.Xfflush(tls, (*crt.XFILE)(Xstdout)) 221 | _i += 1 222 | goto _30 223 | _33: 224 | bin.Xsqlite3_close(tls, (*bin.Xsqlite3)(_db)) 225 | bin.Xsqlite3_free(tls, unsafe.Pointer(_aInfo)) 226 | crt.Xprintf(tls, str(962), _nErr, _nTest) 227 | return _nErr 228 | } 229 | 230 | // C comment 231 | // /* 232 | // ** Run a SQL statements. Panic if unable. 233 | // */ 234 | func _run_sql(tls *crt.TLS, _p *XWorkerInfo, _zFormat *int8, args ...interface{}) { 235 | var _rc, _i, _nRetry int32 236 | var _zSql *int8 237 | var _pStmt unsafe.Pointer 238 | var _ap []interface{} 239 | _pStmt = nil 240 | _nRetry = int32(0) 241 | _ap = args 242 | _zSql = bin.Xsqlite3_vmprintf(tls, _zFormat, _ap) 243 | _ap = nil 244 | _check_oom(tls, unsafe.Pointer(_zSql)) 245 | _i = int32(0) 246 | _0: 247 | if _i >= int32(1000) { 248 | goto _3 249 | } 250 | _rc = bin.Xsqlite3_prepare_v2(tls, (*bin.Xsqlite3)(_p.Xdb), _zSql, int32(-1), &_pStmt, nil) 251 | if _rc == int32(0) { 252 | goto _3 253 | } 254 | _i += 1 255 | goto _0 256 | _3: 257 | if _rc != int32(0) { 258 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(991), _rc, bin.Xsqlite3_extended_errcode(tls, (*bin.Xsqlite3)(_p.Xdb)), unsafe.Pointer(bin.Xsqlite3_errmsg(tls, (*bin.Xsqlite3)(_p.Xdb))), unsafe.Pointer(_zSql)) 259 | crt.Xexit(tls, int32(1)) 260 | } 261 | _worker_trace(tls, _p, str(1036), unsafe.Pointer(_zSql)) 262 | _6: 263 | if store3(&_rc, bin.Xsqlite3_step(tls, _pStmt)) == int32(101) { 264 | goto _7 265 | } 266 | if (_rc&int32(255)) != int32(5) && (_rc&int32(255)) != int32(6) { 267 | goto _9 268 | } 269 | bin.Xsqlite3_reset(tls, _pStmt) 270 | _nRetry += 1 271 | if _nRetry < int32(10) { 272 | _worker_trace(tls, _p, str(1049), _nRetry, unsafe.Pointer(_zSql)) 273 | crt.Xsched_yield(tls) 274 | goto _6 275 | } 276 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(1067), _p.Xtid, unsafe.Pointer(_zSql)) 277 | crt.Xexit(tls, int32(1)) 278 | _9: 279 | if _rc != int32(100) { 280 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(1109), _rc, bin.Xsqlite3_extended_errcode(tls, (*bin.Xsqlite3)(_p.Xdb)), unsafe.Pointer(bin.Xsqlite3_errmsg(tls, (*bin.Xsqlite3)(_p.Xdb))), unsafe.Pointer(_zSql)) 281 | crt.Xexit(tls, int32(1)) 282 | } 283 | goto _6 284 | _7: 285 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zSql)) 286 | bin.Xsqlite3_finalize(tls, _pStmt) 287 | } 288 | 289 | // C comment 290 | // /* 291 | // ** Report an OOM error and die if the argument is NULL 292 | // */ 293 | func _check_oom(tls *crt.TLS, _x unsafe.Pointer) { 294 | if _x == nil { 295 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(1151)) 296 | crt.Xexit(tls, int32(1)) 297 | } 298 | } 299 | 300 | // C comment 301 | // /* 302 | // ** Print a trace message for a worker 303 | // */ 304 | func _worker_trace(tls *crt.TLS, _p *XWorkerInfo, _zFormat *int8, args ...interface{}) { 305 | var _zMsg *int8 306 | var _ap []interface{} 307 | if (_p.XwkrFlags & uint32(4)) == (0) { 308 | return 309 | } 310 | _ap = args 311 | _zMsg = bin.Xsqlite3_vmprintf(tls, _zFormat, _ap) 312 | _check_oom(tls, unsafe.Pointer(_zMsg)) 313 | _ap = nil 314 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(1166), _p.Xtid, unsafe.Pointer(_zMsg)) 315 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zMsg)) 316 | } 317 | 318 | // C comment 319 | // /* 320 | // ** Allocate memory. If the allocation fails, print an error message and 321 | // ** kill the process. 322 | // */ 323 | func _safe_malloc(tls *crt.TLS, _sz int32) (r0 unsafe.Pointer) { 324 | var _x unsafe.Pointer 325 | _x = bin.Xsqlite3_malloc(tls, func() int32 { 326 | if _sz > int32(0) { 327 | return _sz 328 | } 329 | return int32(1) 330 | }()) 331 | _check_oom(tls, _x) 332 | return _x 333 | } 334 | 335 | // C comment 336 | // /* 337 | // ** Each thread runs the following function. 338 | // */ 339 | func _worker_thread(tls *crt.TLS, _pArg unsafe.Pointer) (r0 unsafe.Pointer) { 340 | var _iOuter, _i, _rc int32 341 | var _pStmt unsafe.Pointer 342 | var _p *XWorkerInfo 343 | _p = (*XWorkerInfo)(_pArg) 344 | crt.Xprintf(tls, str(1183), _p.Xtid) 345 | crt.Xfflush(tls, (*crt.XFILE)(Xstdout)) 346 | _iOuter = int32(1) 347 | _0: 348 | if _iOuter > _p.XnWorker { 349 | goto _3 350 | } 351 | _worker_open_connection(tls, _p, _iOuter) 352 | _i = int32(0) 353 | _4: 354 | if _i >= int32(4) { 355 | goto _7 356 | } 357 | _worker_add_content(tls, _p, (_i*int32(100))+int32(1), (_i+int32(1))*int32(100), ((_p.Xtid+_iOuter)%int32(3))+int32(1)) 358 | _worker_add_content(tls, _p, (_i*int32(100))+int32(1), (_i+int32(1))*int32(100), (((_p.Xtid+_iOuter)+int32(1))%int32(3))+int32(1)) 359 | _worker_add_content(tls, _p, (_i*int32(100))+int32(1), (_i+int32(1))*int32(100), (((_p.Xtid+_iOuter)+int32(2))%int32(3))+int32(1)) 360 | _i += 1 361 | goto _4 362 | _7: 363 | _pStmt = _prep_sql(tls, _p.Xdb, str(1202), _p.Xtid) 364 | _worker_trace(tls, _p, str(1239), unsafe.Pointer(bin.Xsqlite3_sql(tls, _pStmt))) 365 | _rc = bin.Xsqlite3_step(tls, _pStmt) 366 | if _rc != int32(100) { 367 | _worker_error(tls, _p, str(1250), unsafe.Pointer(bin.Xsqlite3_sql(tls, _pStmt))) 368 | goto _10 369 | } 370 | if bin.Xsqlite3_column_int(tls, _pStmt, int32(0)) != int32(400) { 371 | _worker_error(tls, _p, str(1269), bin.Xsqlite3_column_int(tls, _pStmt, int32(0))) 372 | } 373 | _10: 374 | bin.Xsqlite3_finalize(tls, _pStmt) 375 | if _p.XnErr != 0 { 376 | goto _3 377 | } 378 | if ((_iOuter + _p.Xtid) % int32(3)) == int32(0) { 379 | bin.Xsqlite3_db_release_memory(tls, (*bin.Xsqlite3)(_p.Xdb)) 380 | _p.XnTest += 1 381 | } 382 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 383 | _run_sql(tls, _p, str(1286)) 384 | _run_sql(tls, _p, str(1293)) 385 | _run_sql(tls, _p, str(1325)) 386 | _run_sql(tls, _p, str(1357)) 387 | _run_sql(tls, _p, str(1389)) 388 | _p.XnTest += 1 389 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 390 | if _iOuter == _p.Xtid { 391 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 392 | _run_sql(tls, _p, str(1399)) 393 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 394 | } 395 | _pStmt = _prep_sql(tls, _p.Xdb, str(1406), _p.Xtid, _p.Xtid, _p.Xtid) 396 | _worker_trace(tls, _p, str(1239), unsafe.Pointer(bin.Xsqlite3_sql(tls, _pStmt))) 397 | _i = int32(0) 398 | _14: 399 | if _i >= _p.XnWorker { 400 | goto _17 401 | } 402 | _rc = bin.Xsqlite3_step(tls, _pStmt) 403 | if _rc != int32(100) { 404 | _worker_error(tls, _p, str(1250), unsafe.Pointer(bin.Xsqlite3_sql(tls, _pStmt))) 405 | goto _17 406 | } 407 | crt.Xsched_yield(tls) 408 | _i += 1 409 | goto _14 410 | _17: 411 | bin.Xsqlite3_finalize(tls, _pStmt) 412 | if _p.XnErr != 0 { 413 | goto _3 414 | } 415 | _worker_delete_all_content(tls, _p, (_p.Xtid+_iOuter)%int32(2)) 416 | _worker_close_connection(tls, _p) 417 | _p.Xdb = nil 418 | _iOuter += 1 419 | goto _0 420 | _3: 421 | _worker_close_connection(tls, _p) 422 | crt.Xprintf(tls, str(1552), _p.Xtid) 423 | crt.Xfflush(tls, (*crt.XFILE)(Xstdout)) 424 | return nil 425 | } 426 | 427 | // C comment 428 | // /* 429 | // ** Open the database connection for WorkerInfo. The order in which 430 | // ** the files are opened is a function of the tid value. 431 | // */ 432 | func _worker_open_connection(tls *crt.TLS, _p *XWorkerInfo, _iCnt int32) { 433 | var _x, _rc int32 434 | var _zFile *int8 435 | _x = (_p.Xtid + _iCnt) % int32(6) 436 | _zFile = bin.Xsqlite3_mprintf(tls, str(1572), int32(*elem4((*uint8)(unsafe.Pointer(elem5((*[3]uint8)(unsafe.Pointer(&_worker_open_connectionØ00aOrderØ001)), uintptr(_x)))), 0))) 437 | _check_oom(tls, unsafe.Pointer(_zFile)) 438 | _worker_trace(tls, _p, str(1586), unsafe.Pointer(_zFile)) 439 | _rc = bin.Xsqlite3_open_v2(tls, _zFile, (**bin.Xsqlite3)(unsafe.Pointer(&_p.Xdb)), int32(131074), nil) 440 | if _rc != int32(0) { 441 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(1594), unsafe.Pointer(_zFile), _p.Xtid) 442 | crt.Xexit(tls, int32(1)) 443 | } 444 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zFile)) 445 | _run_sql(tls, _p, str(1634)) 446 | bin.Xsqlite3_busy_timeout(tls, (*bin.Xsqlite3)(_p.Xdb), int32(10000)) 447 | _run_sql(tls, _p, str(1662)) 448 | _run_sql(tls, _p, str(1686), int32(*elem4((*uint8)(unsafe.Pointer(elem5((*[3]uint8)(unsafe.Pointer(&_worker_open_connectionØ00aOrderØ001)), uintptr(_x)))), uintptr(1)))) 449 | _run_sql(tls, _p, str(1717), int32(*elem4((*uint8)(unsafe.Pointer(elem5((*[3]uint8)(unsafe.Pointer(&_worker_open_connectionØ00aOrderØ001)), uintptr(_x)))), uintptr(2)))) 450 | } 451 | 452 | var _worker_open_connectionØ00aOrderØ001 [6][3]uint8 453 | 454 | func init() { 455 | _worker_open_connectionØ00aOrderØ001 = [6][3]uint8{[3]uint8{uint8(1), uint8(2), uint8(3)}, [3]uint8{uint8(1), uint8(3), uint8(2)}, [3]uint8{uint8(2), uint8(1), uint8(3)}, [3]uint8{uint8(2), uint8(3), uint8(1)}, [3]uint8{uint8(3), uint8(1), uint8(2)}, [3]uint8{uint8(3), uint8(2), uint8(1)}} 456 | } 457 | 458 | // C comment 459 | // /* 460 | // ** Create rows mn through mx in table iTab for the given worker 461 | // */ 462 | func _worker_add_content(tls *crt.TLS, _p *XWorkerInfo, _mn int32, _mx int32, _iTab int32) { 463 | var _zTabDef *int8 464 | switch _iTab { 465 | case int32(1): 466 | goto _1 467 | case int32(2): 468 | goto _2 469 | case int32(3): 470 | goto _3 471 | default: 472 | goto _4 473 | } 474 | 475 | _1: 476 | _zTabDef = str(1748) 477 | goto _4 478 | _2: 479 | _zTabDef = str(1765) 480 | goto _4 481 | _3: 482 | _zTabDef = str(1782) 483 | goto _4 484 | _4: 485 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 486 | _run_sql(tls, _p, str(1799), _mn, _mx, unsafe.Pointer(_zTabDef), _p.Xtid) 487 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 488 | _p.XnTest += 1 489 | } 490 | 491 | // C comment 492 | // /* 493 | // ** Prepare a single SQL query 494 | // */ 495 | func _prep_sql(tls *crt.TLS, _db unsafe.Pointer, _zFormat *int8, args ...interface{}) (r0 unsafe.Pointer) { 496 | var _rc, _i int32 497 | var _zSql *int8 498 | var _pStmt unsafe.Pointer 499 | var _ap []interface{} 500 | _pStmt = nil 501 | _ap = args 502 | _zSql = bin.Xsqlite3_vmprintf(tls, _zFormat, _ap) 503 | _ap = nil 504 | _check_oom(tls, unsafe.Pointer(_zSql)) 505 | _i = int32(0) 506 | _0: 507 | if _i >= int32(1000) { 508 | goto _3 509 | } 510 | _rc = bin.Xsqlite3_prepare_v2(tls, (*bin.Xsqlite3)(_db), _zSql, int32(-1), &_pStmt, nil) 511 | if _rc == int32(0) { 512 | goto _3 513 | } 514 | _i += 1 515 | goto _0 516 | _3: 517 | if _rc != int32(0) { 518 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(991), _rc, bin.Xsqlite3_extended_errcode(tls, (*bin.Xsqlite3)(_db)), unsafe.Pointer(bin.Xsqlite3_errmsg(tls, (*bin.Xsqlite3)(_db))), unsafe.Pointer(_zSql)) 519 | crt.Xexit(tls, int32(1)) 520 | } 521 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zSql)) 522 | return _pStmt 523 | } 524 | 525 | // C comment 526 | // /* 527 | // ** Set an error message on a worker 528 | // */ 529 | func _worker_error(tls *crt.TLS, _p *XWorkerInfo, _zFormat *int8, args ...interface{}) { 530 | var _ap []interface{} 531 | _p.XnErr += 1 532 | bin.Xsqlite3_free(tls, unsafe.Pointer(_p.XzMsg)) 533 | _ap = args 534 | _p.XzMsg = bin.Xsqlite3_vmprintf(tls, _zFormat, _ap) 535 | _ap = nil 536 | } 537 | 538 | // C comment 539 | // /* 540 | // ** Delete all content in the three databases associated with a 541 | // ** single thread. Make this happen all in a single transaction if 542 | // ** inTrans is true, or separately for each database if inTrans is 543 | // ** false. 544 | // */ 545 | func _worker_delete_all_content(tls *crt.TLS, _p *XWorkerInfo, _inTrans int32) { 546 | if _inTrans != 0 { 547 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 548 | _run_sql(tls, _p, str(1947)) 549 | _run_sql(tls, _p, str(1953), _p.Xtid) 550 | _run_sql(tls, _p, str(1981), _p.Xtid) 551 | _run_sql(tls, _p, str(2009), _p.Xtid) 552 | _run_sql(tls, _p, str(2037)) 553 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 554 | _p.XnTest += 1 555 | goto _1 556 | } 557 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 558 | _run_sql(tls, _p, str(1953), _p.Xtid) 559 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 560 | _p.XnTest += 1 561 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 562 | _run_sql(tls, _p, str(1981), _p.Xtid) 563 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 564 | _p.XnTest += 1 565 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 566 | _run_sql(tls, _p, str(2009), _p.Xtid) 567 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 568 | _p.XnTest += 1 569 | _1: 570 | } 571 | 572 | // C comment 573 | // /* 574 | // ** Close the worker database connection 575 | // */ 576 | func _worker_close_connection(tls *crt.TLS, _p *XWorkerInfo) { 577 | if _p.Xdb != nil { 578 | _worker_trace(tls, _p, str(2044)) 579 | bin.Xsqlite3_close(tls, (*bin.Xsqlite3)(_p.Xdb)) 580 | _p.Xdb = nil 581 | } 582 | } 583 | 584 | func bool2int(b bool) int32 { 585 | if b { 586 | return 1 587 | } 588 | return 0 589 | } 590 | func bug20530(interface{}) {} //TODO remove when https://github.com/golang/go/issues/20530 is fixed. 591 | func init() { nzf32 *= -1; nzf64 *= -1 } 592 | 593 | var inf = math.Inf(1) 594 | var nzf32 float32 // -0.0 595 | var nzf64 float64 // -0.0 596 | func elem0(a **int8, index uintptr) **int8 { 597 | return (**int8)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 4*index)) 598 | } 599 | func elem5(a *[3]uint8, index uintptr) *[3]uint8 { 600 | return (*[3]uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 3*index)) 601 | } 602 | func elem1(a *int8, index uintptr) *int8 { 603 | return (*int8)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 1*index)) 604 | } 605 | func elem2(a *XWorkerInfo, index uintptr) *XWorkerInfo { 606 | return (*XWorkerInfo)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 40*index)) 607 | } 608 | func elem4(a *uint8, index uintptr) *uint8 { 609 | return (*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 1*index)) 610 | } 611 | func store3(p *int32, v int32) int32 { *p = v; return v } 612 | 613 | type XWorkerInfo struct { 614 | Xtid int32 615 | XnWorker int32 616 | XwkrFlags uint32 617 | XmainDb unsafe.Pointer 618 | Xdb unsafe.Pointer 619 | XnErr int32 620 | XnTest int32 621 | XzMsg *int8 622 | Xid uint32 623 | XpWrMutex unsafe.Pointer 624 | } // t6 struct{tid int32,nWorker int32,wkrFlags uint32,mainDb *struct{},db *struct{},nErr int32,nTest int32,zMsg *int8,id uint32,pWrMutex *struct{}} 625 | func str(n int) *int8 { return (*int8)(unsafe.Pointer(&strTab[n])) } 626 | func wstr(n int) *int32 { return (*int32)(unsafe.Pointer(&strTab[n])) } 627 | 628 | var strTab = []byte("-multithread\x00-serialized\x00-wal\x00-trace\x00unknown command-line option: %s\x0a\x00minimum of 2 threads\x0a\x00extra command-line argument: \"%s\"\x0a\x00usage: %s ?OPTIONS? N\x0aN is the number of threads and must be at least 2.\x0aOptions:\x0a --serialized\x0a --multithread\x0a --wal\x0a --trace\x0a\x00requires a threadsafe build of SQLite\x0a\x00tt4-test1.db\x00tt4-test2.db\x00tt4-test3.db\x00Unable to open test database: tt4-test2.db\x0a\x00PRAGMA journal_mode=WAL\x00PRAGMA synchronous=OFF\x00CREATE TABLE IF NOT EXISTS t1(tid INTEGER, sp, a, b, c)\x00CREATE INDEX t1tid ON t1(tid)\x00CREATE INDEX t1ab ON t1(a,b)\x00ATTACH 'tt4-test2.db' AS 'test2'\x00CREATE TABLE IF NOT EXISTS test2.t2(tid INTEGER, sp, d, e, f)\x00CREATE INDEX test2.t2tid ON t2(tid)\x00CREATE INDEX test2.t2de ON t2(d,e)\x00ATTACH 'tt4-test3.db' AS 'test3'\x00CREATE TABLE IF NOT EXISTS test3.t3(tid INTEGER, sp, x, y, z)\x00CREATE INDEX test3.t3tid ON t3(tid)\x00CREATE INDEX test3.t3xy ON t3(x,y)\x00thread creation failed for thread %d\x0a\x00Joined thread %d: %d errors in %d tests\x00: %s\x0a\x00\x0a\x00Total %d errors in %d tests\x0a\x00SQL error (%d,%d): %s\x0aWhile preparing: [%s]\x0a\x00running [%s]\x00retry %d for [%s]\x00Deadlock in thread %d while running [%s]\x0a\x00SQL error (%d,%d): %s\x0aWhile running [%s]\x0a\x00out of memory\x0a\x00TRACE(%02d): %s\x0a\x00worker %d startup\x0a\x00SELECT count(a) FROM t1 WHERE tid=%d\x00query [%s]\x00Failed to step: %s\x00Wrong result: %d\x00BEGIN;\x00UPDATE t1 SET c=NULL WHERE a=55\x00UPDATE t2 SET f=NULL WHERE d=42\x00UPDATE t3 SET z=NULL WHERE x=31\x00ROLLBACK;\x00VACUUM\x00SELECT t1.rowid, t2.rowid, t3.rowid FROM t1, t2, t3 WHERE t1.tid=%d AND t2.tid=%d AND t3.tid=%d AND t1.a<>t2.d AND t2.d<>t3.x ORDER BY 1, 2, 3\x00worker %d finished\x0a\x00tt4-test%d.db\x00open %s\x00sqlite_open_v2(%s) failed on thread %d\x0a\x00PRAGMA read_uncommitted=ON;\x00PRAGMA synchronous=OFF;\x00ATTACH 'tt4-test%d.db' AS aux1\x00ATTACH 'tt4-test%d.db' AS aux2\x00t1(tid,sp,a,b,c)\x00t2(tid,sp,d,e,f)\x00t3(tid,sp,x,y,z)\x00WITH RECURSIVE\x0a c(i) AS (VALUES(%d) UNION ALL SELECT i+1 FROM c WHERE i<%d)\x0aINSERT INTO %s SELECT %d, zeroblob(3000), i, printf('%%d',i), i FROM c;\x00BEGIN\x00DELETE FROM t1 WHERE tid=%d\x00DELETE FROM t2 WHERE tid=%d\x00DELETE FROM t3 WHERE tid=%d\x00COMMIT\x00close\x00") 629 | -------------------------------------------------------------------------------- /internal/threadtest4/threadtest4_linux_amd64.go: -------------------------------------------------------------------------------- 1 | // Code generated by ccgo. DO NOT EDIT. 2 | 3 | // threadtest4 4 | // /* 5 | // ** 2014-12-11 6 | // ** 7 | // ** The author disclaims copyright to this source code. In place of 8 | // ** a legal notice, here is a blessing: 9 | // ** 10 | // ** May you do good and not evil. 11 | // ** May you find forgiveness for yourself and forgive others. 12 | // ** May you share freely, never taking more than you give. 13 | // ** 14 | // ************************************************************************* 15 | // ** This file implements a simple standalone program used to stress the 16 | // ** SQLite library when accessing the same set of databases simultaneously 17 | // ** from multiple threads in shared-cache mode. 18 | // ** 19 | // ** This test program runs on unix-like systems only. It uses pthreads. 20 | // ** To compile: 21 | // ** 22 | // ** gcc -g -Wall -I. threadtest4.c sqlite3.c -ldl -lpthread 23 | // ** 24 | // ** To run: 25 | // ** 26 | // ** ./a.out 10 27 | // ** 28 | // ** The argument is the number of threads. There are also options, such 29 | // ** as -wal and -multithread and -serialized. 30 | // ** 31 | // ** Consider also compiling with clang instead of gcc and adding the 32 | // ** -fsanitize=thread option. 33 | // */ 34 | package main 35 | 36 | import ( 37 | "math" 38 | "os" 39 | "unsafe" 40 | 41 | "github.com/cznic/ccgo/crt" 42 | "github.com/cznic/sqlite/internal/bin" 43 | ) 44 | 45 | var argv []*int8 46 | 47 | func main() { 48 | for _, v := range os.Args { 49 | argv = append(argv, (*int8)(crt.CString(v))) 50 | } 51 | argv = append(argv, nil) 52 | X_start(crt.NewTLS(), int32(len(os.Args)), &argv[0]) 53 | } 54 | 55 | func X_start(tls *crt.TLS, _argc int32, _argv **int8) { 56 | crt.X__register_stdfiles(tls, Xstdin, Xstdout, Xstderr) 57 | crt.X__builtin_exit(tls, Xmain(tls, _argc, _argv)) 58 | } 59 | 60 | var Xstdin unsafe.Pointer 61 | 62 | func init() { 63 | Xstdin = unsafe.Pointer(&X__stdfiles) 64 | } 65 | 66 | var X__stdfiles [3]unsafe.Pointer 67 | 68 | var Xstdout unsafe.Pointer 69 | 70 | func init() { 71 | Xstdout = unsafe.Pointer(uintptr(unsafe.Pointer(&X__stdfiles)) + 8) 72 | } 73 | 74 | var Xstderr unsafe.Pointer 75 | 76 | func init() { 77 | Xstderr = unsafe.Pointer(uintptr(unsafe.Pointer(&X__stdfiles)) + 16) 78 | } 79 | 80 | func Xmain(tls *crt.TLS, _argc int32, _argv **int8) (r0 int32) { 81 | var _nWorker, _i, _nErr, _nTest, _rc int32 82 | var _wkrFlags uint32 83 | var _1_z *int8 84 | var _db unsafe.Pointer 85 | var _wrMutex crt.Xpthread_mutex_t 86 | var _infoTop XWorkerInfo 87 | var _aInfo, _p *XWorkerInfo 88 | r0 = int32(0) 89 | _nWorker = int32(0) 90 | _wkrFlags = uint32(0) 91 | _nErr = int32(0) 92 | _nTest = int32(0) 93 | _db = nil 94 | bin.Xsqlite3_config(tls, int32(2)) 95 | _i = int32(1) 96 | _0: 97 | if _i >= _argc { 98 | goto _3 99 | } 100 | _1_z = *elem0(_argv, uintptr(_i)) 101 | if int32(*elem1(_1_z, 0)) != int32(45) { 102 | goto _4 103 | } 104 | if (int32(*elem1(_1_z, uintptr(1))) == int32(45)) && (int32(*elem1(_1_z, uintptr(2))) != int32(0)) { 105 | *(*uintptr)(unsafe.Pointer(&_1_z)) += uintptr(1) 106 | } 107 | if crt.Xstrcmp(tls, _1_z, str(0)) == int32(0) { 108 | bin.Xsqlite3_config(tls, int32(2)) 109 | _wkrFlags &= uint32(4294967294) 110 | goto _14 111 | } 112 | if crt.Xstrcmp(tls, _1_z, str(13)) == int32(0) { 113 | bin.Xsqlite3_config(tls, int32(3)) 114 | _wkrFlags |= uint32(1) 115 | goto _14 116 | } 117 | if crt.Xstrcmp(tls, _1_z, str(25)) == int32(0) { 118 | _wkrFlags |= uint32(2) 119 | goto _14 120 | } 121 | if crt.Xstrcmp(tls, _1_z, str(30)) == int32(0) { 122 | _wkrFlags |= uint32(4) 123 | goto _14 124 | } 125 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(37), unsafe.Pointer(*elem0(_argv, uintptr(_i)))) 126 | crt.Xexit(tls, int32(1)) 127 | _14: 128 | goto _20 129 | _4: 130 | if int32(*elem1(_1_z, 0)) < int32(49) || int32(*elem1(_1_z, 0)) > int32(57) || _nWorker != int32(0) { 131 | goto _18 132 | } 133 | _nWorker = crt.Xatoi(tls, _1_z) 134 | if _nWorker < int32(2) { 135 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(70)) 136 | crt.Xexit(tls, int32(1)) 137 | } 138 | goto _20 139 | _18: 140 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(92), unsafe.Pointer(*elem0(_argv, uintptr(_i)))) 141 | crt.Xexit(tls, int32(1)) 142 | _20: 143 | _i += 1 144 | goto _0 145 | _3: 146 | if _nWorker == int32(0) { 147 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(127), unsafe.Pointer(*elem0(_argv, 0))) 148 | crt.Xexit(tls, int32(1)) 149 | } 150 | if bin.Xsqlite3_threadsafe(tls) == 0 { 151 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(260)) 152 | crt.Xexit(tls, int32(1)) 153 | } 154 | bin.Xsqlite3_initialize(tls) 155 | bin.Xsqlite3_enable_shared_cache(tls, int32(1)) 156 | crt.Xpthread_mutex_init(tls, &_wrMutex, nil) 157 | crt.Xunlink(tls, str(299)) 158 | crt.Xunlink(tls, str(312)) 159 | crt.Xunlink(tls, str(325)) 160 | _rc = bin.Xsqlite3_open(tls, str(299), (**bin.Xsqlite3)(unsafe.Pointer(&_db))) 161 | if _rc != int32(0) { 162 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(338)) 163 | crt.Xexit(tls, int32(1)) 164 | } 165 | crt.Xmemset(tls, unsafe.Pointer(&_infoTop), int32(0), uint64(64)) 166 | _infoTop.Xdb = _db 167 | _infoTop.XwkrFlags = _wkrFlags 168 | _p = &_infoTop 169 | if (_wkrFlags & uint32(2)) != 0 { 170 | _run_sql(tls, _p, str(382)) 171 | } 172 | _run_sql(tls, _p, str(406)) 173 | _run_sql(tls, _p, str(429)) 174 | _run_sql(tls, _p, str(485)) 175 | _run_sql(tls, _p, str(515)) 176 | _run_sql(tls, _p, str(544)) 177 | _run_sql(tls, _p, str(577)) 178 | _run_sql(tls, _p, str(639)) 179 | _run_sql(tls, _p, str(675)) 180 | _run_sql(tls, _p, str(710)) 181 | _run_sql(tls, _p, str(743)) 182 | _run_sql(tls, _p, str(805)) 183 | _run_sql(tls, _p, str(841)) 184 | _aInfo = (*XWorkerInfo)(_safe_malloc(tls, int32(uint64(64)*uint64(_nWorker)))) 185 | crt.Xmemset(tls, unsafe.Pointer(_aInfo), int32(0), uint64(64)*uint64(_nWorker)) 186 | _i = int32(0) 187 | _25: 188 | if _i >= _nWorker { 189 | goto _28 190 | } 191 | elem2(_aInfo, uintptr(_i)).Xtid = _i + int32(1) 192 | elem2(_aInfo, uintptr(_i)).XnWorker = _nWorker 193 | elem2(_aInfo, uintptr(_i)).XwkrFlags = _wkrFlags 194 | elem2(_aInfo, uintptr(_i)).XmainDb = _db 195 | *(**crt.Xpthread_mutex_t)(unsafe.Pointer(&(elem2(_aInfo, uintptr(_i)).XpWrMutex))) = &_wrMutex 196 | _rc = crt.Xpthread_create(tls, &(elem2(_aInfo, uintptr(_i)).Xid), nil, _worker_thread, unsafe.Pointer(elem2(_aInfo, uintptr(_i)))) 197 | if _rc != int32(0) { 198 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(876), _i+int32(1)) 199 | crt.Xexit(tls, int32(1)) 200 | } 201 | crt.Xsched_yield(tls) 202 | _i += 1 203 | goto _25 204 | _28: 205 | _i = int32(0) 206 | _30: 207 | if _i >= _nWorker { 208 | goto _33 209 | } 210 | crt.Xpthread_join(tls, elem2(_aInfo, uintptr(_i)).Xid, nil) 211 | crt.Xprintf(tls, str(914), elem2(_aInfo, uintptr(_i)).Xtid, elem2(_aInfo, uintptr(_i)).XnErr, elem2(_aInfo, uintptr(_i)).XnTest) 212 | if (elem2(_aInfo, uintptr(_i)).XzMsg) != nil { 213 | crt.Xprintf(tls, str(954), unsafe.Pointer(elem2(_aInfo, uintptr(_i)).XzMsg)) 214 | goto _35 215 | } 216 | crt.Xprintf(tls, str(960)) 217 | _35: 218 | _nErr += elem2(_aInfo, uintptr(_i)).XnErr 219 | _nTest += elem2(_aInfo, uintptr(_i)).XnTest 220 | crt.Xfflush(tls, (*crt.XFILE)(Xstdout)) 221 | _i += 1 222 | goto _30 223 | _33: 224 | bin.Xsqlite3_close(tls, (*bin.Xsqlite3)(_db)) 225 | bin.Xsqlite3_free(tls, unsafe.Pointer(_aInfo)) 226 | crt.Xprintf(tls, str(962), _nErr, _nTest) 227 | return _nErr 228 | } 229 | 230 | // C comment 231 | // /* 232 | // ** Run a SQL statements. Panic if unable. 233 | // */ 234 | func _run_sql(tls *crt.TLS, _p *XWorkerInfo, _zFormat *int8, args ...interface{}) { 235 | var _rc, _i, _nRetry int32 236 | var _zSql *int8 237 | var _pStmt unsafe.Pointer 238 | var _ap []interface{} 239 | _pStmt = nil 240 | _nRetry = int32(0) 241 | _ap = args 242 | _zSql = bin.Xsqlite3_vmprintf(tls, _zFormat, _ap) 243 | _ap = nil 244 | _check_oom(tls, unsafe.Pointer(_zSql)) 245 | _i = int32(0) 246 | _0: 247 | if _i >= int32(1000) { 248 | goto _3 249 | } 250 | _rc = bin.Xsqlite3_prepare_v2(tls, (*bin.Xsqlite3)(_p.Xdb), _zSql, int32(-1), &_pStmt, nil) 251 | if _rc == int32(0) { 252 | goto _3 253 | } 254 | _i += 1 255 | goto _0 256 | _3: 257 | if _rc != int32(0) { 258 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(991), _rc, bin.Xsqlite3_extended_errcode(tls, (*bin.Xsqlite3)(_p.Xdb)), unsafe.Pointer(bin.Xsqlite3_errmsg(tls, (*bin.Xsqlite3)(_p.Xdb))), unsafe.Pointer(_zSql)) 259 | crt.Xexit(tls, int32(1)) 260 | } 261 | _worker_trace(tls, _p, str(1036), unsafe.Pointer(_zSql)) 262 | _6: 263 | if store3(&_rc, bin.Xsqlite3_step(tls, _pStmt)) == int32(101) { 264 | goto _7 265 | } 266 | if (_rc&int32(255)) != int32(5) && (_rc&int32(255)) != int32(6) { 267 | goto _9 268 | } 269 | bin.Xsqlite3_reset(tls, _pStmt) 270 | _nRetry += 1 271 | if _nRetry < int32(10) { 272 | _worker_trace(tls, _p, str(1049), _nRetry, unsafe.Pointer(_zSql)) 273 | crt.Xsched_yield(tls) 274 | goto _6 275 | } 276 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(1067), _p.Xtid, unsafe.Pointer(_zSql)) 277 | crt.Xexit(tls, int32(1)) 278 | _9: 279 | if _rc != int32(100) { 280 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(1109), _rc, bin.Xsqlite3_extended_errcode(tls, (*bin.Xsqlite3)(_p.Xdb)), unsafe.Pointer(bin.Xsqlite3_errmsg(tls, (*bin.Xsqlite3)(_p.Xdb))), unsafe.Pointer(_zSql)) 281 | crt.Xexit(tls, int32(1)) 282 | } 283 | goto _6 284 | _7: 285 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zSql)) 286 | bin.Xsqlite3_finalize(tls, _pStmt) 287 | } 288 | 289 | // C comment 290 | // /* 291 | // ** Report an OOM error and die if the argument is NULL 292 | // */ 293 | func _check_oom(tls *crt.TLS, _x unsafe.Pointer) { 294 | if _x == nil { 295 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(1151)) 296 | crt.Xexit(tls, int32(1)) 297 | } 298 | } 299 | 300 | // C comment 301 | // /* 302 | // ** Print a trace message for a worker 303 | // */ 304 | func _worker_trace(tls *crt.TLS, _p *XWorkerInfo, _zFormat *int8, args ...interface{}) { 305 | var _zMsg *int8 306 | var _ap []interface{} 307 | if (_p.XwkrFlags & uint32(4)) == (0) { 308 | return 309 | } 310 | _ap = args 311 | _zMsg = bin.Xsqlite3_vmprintf(tls, _zFormat, _ap) 312 | _check_oom(tls, unsafe.Pointer(_zMsg)) 313 | _ap = nil 314 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(1166), _p.Xtid, unsafe.Pointer(_zMsg)) 315 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zMsg)) 316 | } 317 | 318 | // C comment 319 | // /* 320 | // ** Allocate memory. If the allocation fails, print an error message and 321 | // ** kill the process. 322 | // */ 323 | func _safe_malloc(tls *crt.TLS, _sz int32) (r0 unsafe.Pointer) { 324 | var _x unsafe.Pointer 325 | _x = bin.Xsqlite3_malloc(tls, func() int32 { 326 | if _sz > int32(0) { 327 | return _sz 328 | } 329 | return int32(1) 330 | }()) 331 | _check_oom(tls, _x) 332 | return _x 333 | } 334 | 335 | // C comment 336 | // /* 337 | // ** Each thread runs the following function. 338 | // */ 339 | func _worker_thread(tls *crt.TLS, _pArg unsafe.Pointer) (r0 unsafe.Pointer) { 340 | var _iOuter, _i, _rc int32 341 | var _pStmt unsafe.Pointer 342 | var _p *XWorkerInfo 343 | _p = (*XWorkerInfo)(_pArg) 344 | crt.Xprintf(tls, str(1183), _p.Xtid) 345 | crt.Xfflush(tls, (*crt.XFILE)(Xstdout)) 346 | _iOuter = int32(1) 347 | _0: 348 | if _iOuter > _p.XnWorker { 349 | goto _3 350 | } 351 | _worker_open_connection(tls, _p, _iOuter) 352 | _i = int32(0) 353 | _4: 354 | if _i >= int32(4) { 355 | goto _7 356 | } 357 | _worker_add_content(tls, _p, (_i*int32(100))+int32(1), (_i+int32(1))*int32(100), ((_p.Xtid+_iOuter)%int32(3))+int32(1)) 358 | _worker_add_content(tls, _p, (_i*int32(100))+int32(1), (_i+int32(1))*int32(100), (((_p.Xtid+_iOuter)+int32(1))%int32(3))+int32(1)) 359 | _worker_add_content(tls, _p, (_i*int32(100))+int32(1), (_i+int32(1))*int32(100), (((_p.Xtid+_iOuter)+int32(2))%int32(3))+int32(1)) 360 | _i += 1 361 | goto _4 362 | _7: 363 | _pStmt = _prep_sql(tls, _p.Xdb, str(1202), _p.Xtid) 364 | _worker_trace(tls, _p, str(1239), unsafe.Pointer(bin.Xsqlite3_sql(tls, _pStmt))) 365 | _rc = bin.Xsqlite3_step(tls, _pStmt) 366 | if _rc != int32(100) { 367 | _worker_error(tls, _p, str(1250), unsafe.Pointer(bin.Xsqlite3_sql(tls, _pStmt))) 368 | goto _10 369 | } 370 | if bin.Xsqlite3_column_int(tls, _pStmt, int32(0)) != int32(400) { 371 | _worker_error(tls, _p, str(1269), bin.Xsqlite3_column_int(tls, _pStmt, int32(0))) 372 | } 373 | _10: 374 | bin.Xsqlite3_finalize(tls, _pStmt) 375 | if _p.XnErr != 0 { 376 | goto _3 377 | } 378 | if ((_iOuter + _p.Xtid) % int32(3)) == int32(0) { 379 | bin.Xsqlite3_db_release_memory(tls, (*bin.Xsqlite3)(_p.Xdb)) 380 | _p.XnTest += 1 381 | } 382 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 383 | _run_sql(tls, _p, str(1286)) 384 | _run_sql(tls, _p, str(1293)) 385 | _run_sql(tls, _p, str(1325)) 386 | _run_sql(tls, _p, str(1357)) 387 | _run_sql(tls, _p, str(1389)) 388 | _p.XnTest += 1 389 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 390 | if _iOuter == _p.Xtid { 391 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 392 | _run_sql(tls, _p, str(1399)) 393 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 394 | } 395 | _pStmt = _prep_sql(tls, _p.Xdb, str(1406), _p.Xtid, _p.Xtid, _p.Xtid) 396 | _worker_trace(tls, _p, str(1239), unsafe.Pointer(bin.Xsqlite3_sql(tls, _pStmt))) 397 | _i = int32(0) 398 | _14: 399 | if _i >= _p.XnWorker { 400 | goto _17 401 | } 402 | _rc = bin.Xsqlite3_step(tls, _pStmt) 403 | if _rc != int32(100) { 404 | _worker_error(tls, _p, str(1250), unsafe.Pointer(bin.Xsqlite3_sql(tls, _pStmt))) 405 | goto _17 406 | } 407 | crt.Xsched_yield(tls) 408 | _i += 1 409 | goto _14 410 | _17: 411 | bin.Xsqlite3_finalize(tls, _pStmt) 412 | if _p.XnErr != 0 { 413 | goto _3 414 | } 415 | _worker_delete_all_content(tls, _p, (_p.Xtid+_iOuter)%int32(2)) 416 | _worker_close_connection(tls, _p) 417 | _p.Xdb = nil 418 | _iOuter += 1 419 | goto _0 420 | _3: 421 | _worker_close_connection(tls, _p) 422 | crt.Xprintf(tls, str(1552), _p.Xtid) 423 | crt.Xfflush(tls, (*crt.XFILE)(Xstdout)) 424 | return nil 425 | } 426 | 427 | // C comment 428 | // /* 429 | // ** Open the database connection for WorkerInfo. The order in which 430 | // ** the files are opened is a function of the tid value. 431 | // */ 432 | func _worker_open_connection(tls *crt.TLS, _p *XWorkerInfo, _iCnt int32) { 433 | var _x, _rc int32 434 | var _zFile *int8 435 | _x = (_p.Xtid + _iCnt) % int32(6) 436 | _zFile = bin.Xsqlite3_mprintf(tls, str(1572), int32(*elem4((*uint8)(unsafe.Pointer(elem5((*[3]uint8)(unsafe.Pointer(&_worker_open_connectionØ00aOrderØ001)), uintptr(_x)))), 0))) 437 | _check_oom(tls, unsafe.Pointer(_zFile)) 438 | _worker_trace(tls, _p, str(1586), unsafe.Pointer(_zFile)) 439 | _rc = bin.Xsqlite3_open_v2(tls, _zFile, (**bin.Xsqlite3)(unsafe.Pointer(&_p.Xdb)), int32(131074), nil) 440 | if _rc != int32(0) { 441 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(1594), unsafe.Pointer(_zFile), _p.Xtid) 442 | crt.Xexit(tls, int32(1)) 443 | } 444 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zFile)) 445 | _run_sql(tls, _p, str(1634)) 446 | bin.Xsqlite3_busy_timeout(tls, (*bin.Xsqlite3)(_p.Xdb), int32(10000)) 447 | _run_sql(tls, _p, str(1662)) 448 | _run_sql(tls, _p, str(1686), int32(*elem4((*uint8)(unsafe.Pointer(elem5((*[3]uint8)(unsafe.Pointer(&_worker_open_connectionØ00aOrderØ001)), uintptr(_x)))), uintptr(1)))) 449 | _run_sql(tls, _p, str(1717), int32(*elem4((*uint8)(unsafe.Pointer(elem5((*[3]uint8)(unsafe.Pointer(&_worker_open_connectionØ00aOrderØ001)), uintptr(_x)))), uintptr(2)))) 450 | } 451 | 452 | var _worker_open_connectionØ00aOrderØ001 [6][3]uint8 453 | 454 | func init() { 455 | _worker_open_connectionØ00aOrderØ001 = [6][3]uint8{[3]uint8{uint8(1), uint8(2), uint8(3)}, [3]uint8{uint8(1), uint8(3), uint8(2)}, [3]uint8{uint8(2), uint8(1), uint8(3)}, [3]uint8{uint8(2), uint8(3), uint8(1)}, [3]uint8{uint8(3), uint8(1), uint8(2)}, [3]uint8{uint8(3), uint8(2), uint8(1)}} 456 | } 457 | 458 | // C comment 459 | // /* 460 | // ** Create rows mn through mx in table iTab for the given worker 461 | // */ 462 | func _worker_add_content(tls *crt.TLS, _p *XWorkerInfo, _mn int32, _mx int32, _iTab int32) { 463 | var _zTabDef *int8 464 | switch _iTab { 465 | case int32(1): 466 | goto _1 467 | case int32(2): 468 | goto _2 469 | case int32(3): 470 | goto _3 471 | default: 472 | goto _4 473 | } 474 | 475 | _1: 476 | _zTabDef = str(1748) 477 | goto _4 478 | _2: 479 | _zTabDef = str(1765) 480 | goto _4 481 | _3: 482 | _zTabDef = str(1782) 483 | goto _4 484 | _4: 485 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 486 | _run_sql(tls, _p, str(1799), _mn, _mx, unsafe.Pointer(_zTabDef), _p.Xtid) 487 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 488 | _p.XnTest += 1 489 | } 490 | 491 | // C comment 492 | // /* 493 | // ** Prepare a single SQL query 494 | // */ 495 | func _prep_sql(tls *crt.TLS, _db unsafe.Pointer, _zFormat *int8, args ...interface{}) (r0 unsafe.Pointer) { 496 | var _rc, _i int32 497 | var _zSql *int8 498 | var _pStmt unsafe.Pointer 499 | var _ap []interface{} 500 | _pStmt = nil 501 | _ap = args 502 | _zSql = bin.Xsqlite3_vmprintf(tls, _zFormat, _ap) 503 | _ap = nil 504 | _check_oom(tls, unsafe.Pointer(_zSql)) 505 | _i = int32(0) 506 | _0: 507 | if _i >= int32(1000) { 508 | goto _3 509 | } 510 | _rc = bin.Xsqlite3_prepare_v2(tls, (*bin.Xsqlite3)(_db), _zSql, int32(-1), &_pStmt, nil) 511 | if _rc == int32(0) { 512 | goto _3 513 | } 514 | _i += 1 515 | goto _0 516 | _3: 517 | if _rc != int32(0) { 518 | crt.Xfprintf(tls, (*crt.XFILE)(Xstderr), str(991), _rc, bin.Xsqlite3_extended_errcode(tls, (*bin.Xsqlite3)(_db)), unsafe.Pointer(bin.Xsqlite3_errmsg(tls, (*bin.Xsqlite3)(_db))), unsafe.Pointer(_zSql)) 519 | crt.Xexit(tls, int32(1)) 520 | } 521 | bin.Xsqlite3_free(tls, unsafe.Pointer(_zSql)) 522 | return _pStmt 523 | } 524 | 525 | // C comment 526 | // /* 527 | // ** Set an error message on a worker 528 | // */ 529 | func _worker_error(tls *crt.TLS, _p *XWorkerInfo, _zFormat *int8, args ...interface{}) { 530 | var _ap []interface{} 531 | _p.XnErr += 1 532 | bin.Xsqlite3_free(tls, unsafe.Pointer(_p.XzMsg)) 533 | _ap = args 534 | _p.XzMsg = bin.Xsqlite3_vmprintf(tls, _zFormat, _ap) 535 | _ap = nil 536 | } 537 | 538 | // C comment 539 | // /* 540 | // ** Delete all content in the three databases associated with a 541 | // ** single thread. Make this happen all in a single transaction if 542 | // ** inTrans is true, or separately for each database if inTrans is 543 | // ** false. 544 | // */ 545 | func _worker_delete_all_content(tls *crt.TLS, _p *XWorkerInfo, _inTrans int32) { 546 | if _inTrans != 0 { 547 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 548 | _run_sql(tls, _p, str(1947)) 549 | _run_sql(tls, _p, str(1953), _p.Xtid) 550 | _run_sql(tls, _p, str(1981), _p.Xtid) 551 | _run_sql(tls, _p, str(2009), _p.Xtid) 552 | _run_sql(tls, _p, str(2037)) 553 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 554 | _p.XnTest += 1 555 | goto _1 556 | } 557 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 558 | _run_sql(tls, _p, str(1953), _p.Xtid) 559 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 560 | _p.XnTest += 1 561 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 562 | _run_sql(tls, _p, str(1981), _p.Xtid) 563 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 564 | _p.XnTest += 1 565 | crt.Xpthread_mutex_lock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 566 | _run_sql(tls, _p, str(2009), _p.Xtid) 567 | crt.Xpthread_mutex_unlock(tls, (*crt.Xpthread_mutex_t)(_p.XpWrMutex)) 568 | _p.XnTest += 1 569 | _1: 570 | } 571 | 572 | // C comment 573 | // /* 574 | // ** Close the worker database connection 575 | // */ 576 | func _worker_close_connection(tls *crt.TLS, _p *XWorkerInfo) { 577 | if _p.Xdb != nil { 578 | _worker_trace(tls, _p, str(2044)) 579 | bin.Xsqlite3_close(tls, (*bin.Xsqlite3)(_p.Xdb)) 580 | _p.Xdb = nil 581 | } 582 | } 583 | 584 | func bool2int(b bool) int32 { 585 | if b { 586 | return 1 587 | } 588 | return 0 589 | } 590 | func bug20530(interface{}) {} //TODO remove when https://github.com/golang/go/issues/20530 is fixed. 591 | func init() { nzf32 *= -1; nzf64 *= -1 } 592 | 593 | var inf = math.Inf(1) 594 | var nzf32 float32 // -0.0 595 | var nzf64 float64 // -0.0 596 | func elem0(a **int8, index uintptr) **int8 { 597 | return (**int8)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 8*index)) 598 | } 599 | func elem5(a *[3]uint8, index uintptr) *[3]uint8 { 600 | return (*[3]uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 3*index)) 601 | } 602 | func elem1(a *int8, index uintptr) *int8 { 603 | return (*int8)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 1*index)) 604 | } 605 | func elem2(a *XWorkerInfo, index uintptr) *XWorkerInfo { 606 | return (*XWorkerInfo)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 64*index)) 607 | } 608 | func elem4(a *uint8, index uintptr) *uint8 { 609 | return (*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(a)) + 1*index)) 610 | } 611 | func store3(p *int32, v int32) int32 { *p = v; return v } 612 | 613 | type XWorkerInfo struct { 614 | Xtid int32 615 | XnWorker int32 616 | XwkrFlags uint32 617 | XmainDb unsafe.Pointer 618 | Xdb unsafe.Pointer 619 | XnErr int32 620 | XnTest int32 621 | XzMsg *int8 622 | Xid uint64 623 | XpWrMutex unsafe.Pointer 624 | } // t6 struct{tid int32,nWorker int32,wkrFlags uint32,mainDb *struct{},db *struct{},nErr int32,nTest int32,zMsg *int8,id uint64,pWrMutex *struct{}} 625 | func str(n int) *int8 { return (*int8)(unsafe.Pointer(&strTab[n])) } 626 | func wstr(n int) *int32 { return (*int32)(unsafe.Pointer(&strTab[n])) } 627 | 628 | var strTab = []byte("-multithread\x00-serialized\x00-wal\x00-trace\x00unknown command-line option: %s\x0a\x00minimum of 2 threads\x0a\x00extra command-line argument: \"%s\"\x0a\x00usage: %s ?OPTIONS? N\x0aN is the number of threads and must be at least 2.\x0aOptions:\x0a --serialized\x0a --multithread\x0a --wal\x0a --trace\x0a\x00requires a threadsafe build of SQLite\x0a\x00tt4-test1.db\x00tt4-test2.db\x00tt4-test3.db\x00Unable to open test database: tt4-test2.db\x0a\x00PRAGMA journal_mode=WAL\x00PRAGMA synchronous=OFF\x00CREATE TABLE IF NOT EXISTS t1(tid INTEGER, sp, a, b, c)\x00CREATE INDEX t1tid ON t1(tid)\x00CREATE INDEX t1ab ON t1(a,b)\x00ATTACH 'tt4-test2.db' AS 'test2'\x00CREATE TABLE IF NOT EXISTS test2.t2(tid INTEGER, sp, d, e, f)\x00CREATE INDEX test2.t2tid ON t2(tid)\x00CREATE INDEX test2.t2de ON t2(d,e)\x00ATTACH 'tt4-test3.db' AS 'test3'\x00CREATE TABLE IF NOT EXISTS test3.t3(tid INTEGER, sp, x, y, z)\x00CREATE INDEX test3.t3tid ON t3(tid)\x00CREATE INDEX test3.t3xy ON t3(x,y)\x00thread creation failed for thread %d\x0a\x00Joined thread %d: %d errors in %d tests\x00: %s\x0a\x00\x0a\x00Total %d errors in %d tests\x0a\x00SQL error (%d,%d): %s\x0aWhile preparing: [%s]\x0a\x00running [%s]\x00retry %d for [%s]\x00Deadlock in thread %d while running [%s]\x0a\x00SQL error (%d,%d): %s\x0aWhile running [%s]\x0a\x00out of memory\x0a\x00TRACE(%02d): %s\x0a\x00worker %d startup\x0a\x00SELECT count(a) FROM t1 WHERE tid=%d\x00query [%s]\x00Failed to step: %s\x00Wrong result: %d\x00BEGIN;\x00UPDATE t1 SET c=NULL WHERE a=55\x00UPDATE t2 SET f=NULL WHERE d=42\x00UPDATE t3 SET z=NULL WHERE x=31\x00ROLLBACK;\x00VACUUM\x00SELECT t1.rowid, t2.rowid, t3.rowid FROM t1, t2, t3 WHERE t1.tid=%d AND t2.tid=%d AND t3.tid=%d AND t1.a<>t2.d AND t2.d<>t3.x ORDER BY 1, 2, 3\x00worker %d finished\x0a\x00tt4-test%d.db\x00open %s\x00sqlite_open_v2(%s) failed on thread %d\x0a\x00PRAGMA read_uncommitted=ON;\x00PRAGMA synchronous=OFF;\x00ATTACH 'tt4-test%d.db' AS aux1\x00ATTACH 'tt4-test%d.db' AS aux2\x00t1(tid,sp,a,b,c)\x00t2(tid,sp,d,e,f)\x00t3(tid,sp,x,y,z)\x00WITH RECURSIVE\x0a c(i) AS (VALUES(%d) UNION ALL SELECT i+1 FROM c WHERE i<%d)\x0aINSERT INTO %s SELECT %d, zeroblob(3000), i, printf('%%d',i), i FROM c;\x00BEGIN\x00DELETE FROM t1 WHERE tid=%d\x00DELETE FROM t2 WHERE tid=%d\x00DELETE FROM t3 WHERE tid=%d\x00COMMIT\x00close\x00") 629 | -------------------------------------------------------------------------------- /sqlite.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Sqlite Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sqlite 6 | 7 | import ( 8 | "bytes" 9 | "database/sql" 10 | "database/sql/driver" 11 | "fmt" 12 | "io" 13 | "math" 14 | "os" 15 | "runtime" 16 | "sync" 17 | "time" 18 | "unsafe" 19 | 20 | "github.com/cznic/ccgo/crt" 21 | "github.com/cznic/sqlite/internal/bin" 22 | "golang.org/x/net/context" 23 | ) 24 | 25 | var ( 26 | _ driver.Conn = (*conn)(nil) 27 | _ driver.Driver = (*Driver)(nil) 28 | _ driver.Execer = (*conn)(nil) 29 | _ driver.Queryer = (*conn)(nil) 30 | _ driver.Result = (*result)(nil) 31 | _ driver.Rows = (*rows)(nil) 32 | _ driver.Stmt = (*stmt)(nil) 33 | _ driver.Tx = (*tx)(nil) 34 | ) 35 | 36 | const ( 37 | driverName = "sqlite" 38 | ptrSize = 1 << (^uintptr(0)>>32&1 + ^uintptr(0)>>16&1 + ^uintptr(0)>>8&1 + 3) / 8 39 | ) 40 | 41 | func init() { 42 | tls := crt.NewTLS() 43 | crt.X__register_stdfiles(tls, bin.Xstdin, bin.Xstdout, bin.Xstderr) 44 | if bin.Xsqlite3_threadsafe(tls) == 0 { 45 | panic(fmt.Errorf("sqlite: thread safety configuration error")) 46 | } 47 | 48 | if bin.Xsqlite3_config( 49 | tls, 50 | bin.XSQLITE_CONFIG_LOG, 51 | func(tls *crt.TLS, pArg unsafe.Pointer, iErrCode int32, zMsg *int8) { 52 | fmt.Fprintf(os.Stderr, "%v(%#x): %s\n", iErrCode, iErrCode, crt.GoString(zMsg)) 53 | }, 54 | unsafe.Pointer(nil), 55 | ) != 0 { 56 | panic("sqlite: cannot configure error log callback") 57 | } 58 | 59 | sql.Register(driverName, newDrv()) 60 | } 61 | 62 | func tracer(rx interface{}, format string, args ...interface{}) { 63 | var b bytes.Buffer 64 | _, file, line, _ := runtime.Caller(1) 65 | fmt.Fprintf(&b, "%v:%v: (%[3]T)(%[3]p).", file, line, rx) 66 | fmt.Fprintf(&b, format, args...) 67 | fmt.Fprintf(os.Stderr, "%s\n", b.Bytes()) 68 | } 69 | 70 | type result struct { 71 | *stmt 72 | lastInsertID int64 73 | rowsAffected int 74 | } 75 | 76 | func (r *result) String() string { 77 | return fmt.Sprintf("&%T@%p{stmt: %p, LastInsertId: %v, RowsAffected: %v}", *r, r, r.stmt, r.lastInsertID, r.rowsAffected) 78 | } 79 | 80 | func newResult(s *stmt) (_ *result, err error) { 81 | r := &result{stmt: s} 82 | if r.rowsAffected, err = r.changes(); err != nil { 83 | return nil, err 84 | } 85 | 86 | if r.lastInsertID, err = r.lastInsertRowID(); err != nil { 87 | return nil, err 88 | } 89 | 90 | return r, nil 91 | } 92 | 93 | // sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); 94 | func (r *result) lastInsertRowID() (v int64, _ error) { 95 | return bin.Xsqlite3_last_insert_rowid(r.tls, r.pdb()), nil 96 | } 97 | 98 | // int sqlite3_changes(sqlite3*); 99 | func (r *result) changes() (int, error) { 100 | v := bin.Xsqlite3_changes(r.tls, r.pdb()) 101 | return int(v), nil 102 | } 103 | 104 | // LastInsertId returns the database's auto-generated ID after, for example, an 105 | // INSERT into a table with primary key. 106 | func (r *result) LastInsertId() (int64, error) { 107 | if r == nil { 108 | return 0, nil 109 | } 110 | 111 | return r.lastInsertID, nil 112 | } 113 | 114 | // RowsAffected returns the number of rows affected by the query. 115 | func (r *result) RowsAffected() (int64, error) { 116 | if r == nil { 117 | return 0, nil 118 | } 119 | 120 | return int64(r.rowsAffected), nil 121 | } 122 | 123 | type rows struct { 124 | *stmt 125 | columns []string 126 | rc0 int 127 | pstmt unsafe.Pointer 128 | doStep bool 129 | } 130 | 131 | func (r *rows) String() string { 132 | 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) 133 | } 134 | 135 | func newRows(s *stmt, pstmt unsafe.Pointer, rc0 int) (*rows, error) { 136 | r := &rows{ 137 | stmt: s, 138 | pstmt: pstmt, 139 | rc0: rc0, 140 | } 141 | 142 | n, err := r.columnCount() 143 | if err != nil { 144 | return nil, err 145 | } 146 | 147 | r.columns = make([]string, n) 148 | for i := range r.columns { 149 | if r.columns[i], err = r.columnName(i); err != nil { 150 | return nil, err 151 | } 152 | } 153 | 154 | return r, nil 155 | } 156 | 157 | // Columns returns the names of the columns. The number of columns of the 158 | // result is inferred from the length of the slice. If a particular column name 159 | // isn't known, an empty string should be returned for that entry. 160 | func (r *rows) Columns() (c []string) { 161 | if trace { 162 | defer func() { 163 | tracer(r, "Columns(): %v", c) 164 | }() 165 | } 166 | return r.columns 167 | } 168 | 169 | // Close closes the rows iterator. 170 | func (r *rows) Close() (err error) { 171 | if trace { 172 | defer func() { 173 | tracer(r, "Close(): %v", err) 174 | }() 175 | } 176 | return r.finalize(r.pstmt) 177 | } 178 | 179 | // Next is called to populate the next row of data into the provided slice. The 180 | // provided slice will be the same size as the Columns() are wide. 181 | // 182 | // Next should return io.EOF when there are no more rows. 183 | func (r *rows) Next(dest []driver.Value) (err error) { 184 | if trace { 185 | defer func() { 186 | tracer(r, "Next(%v): %v", dest, err) 187 | }() 188 | } 189 | rc := r.rc0 190 | if r.doStep { 191 | if rc, err = r.step(r.pstmt); err != nil { 192 | return err 193 | } 194 | } 195 | 196 | r.doStep = true 197 | 198 | switch rc { 199 | case bin.XSQLITE_ROW: 200 | if g, e := len(dest), len(r.columns); g != e { 201 | return fmt.Errorf("Next(): have %v destination values, expected %v", g, e) 202 | } 203 | 204 | for i := range dest { 205 | ct, err := r.columnType(i) 206 | if err != nil { 207 | return err 208 | } 209 | 210 | switch ct { 211 | case bin.XSQLITE_INTEGER: 212 | v, err := r.columnInt64(i) 213 | if err != nil { 214 | return err 215 | } 216 | 217 | dest[i] = v 218 | case bin.XSQLITE_FLOAT: 219 | v, err := r.columnDouble(i) 220 | if err != nil { 221 | return err 222 | } 223 | 224 | dest[i] = v 225 | case bin.XSQLITE_TEXT: 226 | v, err := r.columnText(i) 227 | if err != nil { 228 | return err 229 | } 230 | 231 | dest[i] = v 232 | case bin.XSQLITE_BLOB: 233 | v, err := r.columnBlob(i) 234 | if err != nil { 235 | return err 236 | } 237 | 238 | dest[i] = v 239 | case bin.XSQLITE_NULL: 240 | dest[i] = nil 241 | default: 242 | panic("internal error") 243 | } 244 | } 245 | return nil 246 | case bin.XSQLITE_DONE: 247 | return io.EOF 248 | default: 249 | return r.errstr(int32(rc)) 250 | } 251 | } 252 | 253 | // int sqlite3_column_bytes(sqlite3_stmt*, int iCol); 254 | func (r *rows) columnBytes(iCol int) (_ int, err error) { 255 | v := bin.Xsqlite3_column_bytes(r.tls, r.pstmt, int32(iCol)) 256 | return int(v), nil 257 | } 258 | 259 | // const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); 260 | func (r *rows) columnBlob(iCol int) (v []byte, err error) { 261 | p := bin.Xsqlite3_column_blob(r.tls, r.pstmt, int32(iCol)) 262 | len, err := r.columnBytes(iCol) 263 | if err != nil { 264 | return nil, err 265 | } 266 | 267 | return crt.GoBytesLen((*int8)(p), len), nil 268 | } 269 | 270 | // const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); 271 | func (r *rows) columnText(iCol int) (v string, err error) { 272 | p := bin.Xsqlite3_column_text(r.tls, r.pstmt, int32(iCol)) 273 | len, err := r.columnBytes(iCol) 274 | if err != nil { 275 | return "", err 276 | } 277 | 278 | return crt.GoStringLen((*int8)(unsafe.Pointer(p)), len), nil 279 | } 280 | 281 | // double sqlite3_column_double(sqlite3_stmt*, int iCol); 282 | func (r *rows) columnDouble(iCol int) (v float64, err error) { 283 | v = bin.Xsqlite3_column_double(r.tls, r.pstmt, int32(iCol)) 284 | return v, nil 285 | } 286 | 287 | // sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); 288 | func (r *rows) columnInt64(iCol int) (v int64, err error) { 289 | v = bin.Xsqlite3_column_int64(r.tls, r.pstmt, int32(iCol)) 290 | return v, nil 291 | } 292 | 293 | // int sqlite3_column_type(sqlite3_stmt*, int iCol); 294 | func (r *rows) columnType(iCol int) (_ int, err error) { 295 | v := bin.Xsqlite3_column_type(r.tls, r.pstmt, int32(iCol)) 296 | return int(v), nil 297 | } 298 | 299 | // int sqlite3_column_count(sqlite3_stmt *pStmt); 300 | func (r *rows) columnCount() (_ int, err error) { 301 | v := bin.Xsqlite3_column_count(r.tls, r.pstmt) 302 | return int(v), nil 303 | } 304 | 305 | // const char *sqlite3_column_name(sqlite3_stmt*, int N); 306 | func (r *rows) columnName(n int) (string, error) { 307 | p := bin.Xsqlite3_column_name(r.tls, r.pstmt, int32(n)) 308 | return crt.GoString(p), nil 309 | } 310 | 311 | type stmt struct { 312 | *conn 313 | allocs []unsafe.Pointer 314 | psql *int8 315 | ppstmt *unsafe.Pointer 316 | pzTail **int8 317 | } 318 | 319 | func (s *stmt) String() string { 320 | return fmt.Sprintf("&%T@%p{conn: %p, alloc %v, psql: %#x, ppstmt: %#x, pzTail: %#x}", *s, s, s.conn, s.allocs, s.psql, s.ppstmt, s.pzTail) 321 | } 322 | 323 | func newStmt(c *conn, sql string) (*stmt, error) { 324 | s := &stmt{conn: c} 325 | psql, err := s.cString(sql) 326 | if err != nil { 327 | return nil, err 328 | } 329 | 330 | s.psql = psql 331 | ppstmt, err := s.malloc(ptrSize) 332 | if err != nil { 333 | s.free(unsafe.Pointer(psql)) 334 | return nil, err 335 | } 336 | 337 | s.ppstmt = (*unsafe.Pointer)(ppstmt) 338 | pzTail, err := s.malloc(ptrSize) 339 | if err != nil { 340 | s.free(unsafe.Pointer(psql)) 341 | s.free(ppstmt) 342 | return nil, err 343 | } 344 | 345 | s.pzTail = (**int8)(pzTail) 346 | return s, nil 347 | } 348 | 349 | // Close closes the statement. 350 | // 351 | // As of Go 1.1, a Stmt will not be closed if it's in use by any queries. 352 | func (s *stmt) Close() (err error) { 353 | if trace { 354 | defer func() { 355 | tracer(s, "Close(): %v", err) 356 | }() 357 | } 358 | if s.psql != nil { 359 | err = s.free(unsafe.Pointer(s.psql)) 360 | s.psql = nil 361 | } 362 | if s.ppstmt != nil { 363 | if err2 := s.free(unsafe.Pointer(s.ppstmt)); err2 != nil && err == nil { 364 | err = err2 365 | } 366 | s.ppstmt = nil 367 | } 368 | if s.pzTail != nil { 369 | if err2 := s.free(unsafe.Pointer(s.pzTail)); err2 != nil && err == nil { 370 | err = err2 371 | } 372 | s.pzTail = nil 373 | } 374 | for _, v := range s.allocs { 375 | if err2 := s.free(v); err2 != nil && err == nil { 376 | err = err2 377 | } 378 | } 379 | s.allocs = nil 380 | return err 381 | } 382 | 383 | // NumInput returns the number of placeholder parameters. 384 | // 385 | // If NumInput returns >= 0, the sql package will sanity check argument counts 386 | // from callers and return errors to the caller before the statement's Exec or 387 | // Query methods are called. 388 | // 389 | // NumInput may also return -1, if the driver doesn't know its number of 390 | // placeholders. In that case, the sql package will not sanity check Exec or 391 | // Query argument counts. 392 | func (s *stmt) NumInput() (n int) { 393 | if trace { 394 | defer func() { 395 | tracer(s, "NumInput(): %v", n) 396 | }() 397 | } 398 | return -1 399 | } 400 | 401 | // Exec executes a query that doesn't return rows, such as an INSERT or UPDATE. 402 | func (s *stmt) Exec(args []driver.Value) (driver.Result, error) { 403 | return s.exec(context.Background(), toNamedValues(args)) 404 | } 405 | 406 | func (s *stmt) exec(ctx context.Context, args []namedValue) (r driver.Result, err error) { 407 | if trace { 408 | defer func(args []namedValue) { 409 | tracer(s, "Exec(%v): (%v, %v)", args, r, err) 410 | }(args) 411 | } 412 | 413 | var pstmt unsafe.Pointer 414 | 415 | donech := make(chan struct{}) 416 | defer close(donech) 417 | go func() { 418 | select { 419 | case <-ctx.Done(): 420 | if pstmt != nil { 421 | s.interrupt(s.pdb()) 422 | } 423 | case <-donech: 424 | } 425 | }() 426 | 427 | for psql := s.psql; *psql != 0; psql = *s.pzTail { 428 | if err := s.prepareV2(psql); err != nil { 429 | return nil, err 430 | } 431 | 432 | pstmt = *s.ppstmt 433 | if pstmt == nil { 434 | continue 435 | } 436 | 437 | n, err := s.bindParameterCount(pstmt) 438 | if err != nil { 439 | return nil, err 440 | } 441 | 442 | if n != 0 { 443 | if err = s.bind(pstmt, n, args); err != nil { 444 | return nil, err 445 | } 446 | } 447 | 448 | rc, err := s.step(pstmt) 449 | if err != nil { 450 | s.finalize(pstmt) 451 | return nil, err 452 | } 453 | 454 | switch rc & 0xff { 455 | case bin.XSQLITE_DONE, bin.XSQLITE_ROW: 456 | if err := s.finalize(pstmt); err != nil { 457 | return nil, err 458 | } 459 | default: 460 | err = s.errstr(int32(rc)) 461 | s.finalize(pstmt) 462 | return nil, err 463 | } 464 | } 465 | return newResult(s) 466 | } 467 | 468 | func (s *stmt) Query(args []driver.Value) (driver.Rows, error) { 469 | return s.query(context.Background(), toNamedValues(args)) 470 | } 471 | 472 | func (s *stmt) query(ctx context.Context, args []namedValue) (r driver.Rows, err error) { 473 | if trace { 474 | defer func(args []namedValue) { 475 | tracer(s, "Query(%v): (%v, %v)", args, r, err) 476 | }(args) 477 | } 478 | 479 | var pstmt, rowStmt unsafe.Pointer 480 | var rc0 int 481 | 482 | donech := make(chan struct{}) 483 | defer close(donech) 484 | go func() { 485 | select { 486 | case <-ctx.Done(): 487 | if pstmt != nil { 488 | s.interrupt(s.pdb()) 489 | } 490 | case <-donech: 491 | } 492 | }() 493 | 494 | for psql := s.psql; *psql != 0; psql = *s.pzTail { 495 | if err := s.prepareV2(psql); err != nil { 496 | return nil, err 497 | } 498 | 499 | pstmt = *s.ppstmt 500 | if pstmt == nil { 501 | continue 502 | } 503 | 504 | n, err := s.bindParameterCount(pstmt) 505 | if err != nil { 506 | return nil, err 507 | } 508 | 509 | if n != 0 { 510 | if err = s.bind(pstmt, n, args); err != nil { 511 | return nil, err 512 | } 513 | } 514 | 515 | rc, err := s.step(pstmt) 516 | if err != nil { 517 | s.finalize(pstmt) 518 | return nil, err 519 | } 520 | 521 | switch rc { 522 | case bin.XSQLITE_ROW: 523 | if rowStmt != nil { 524 | if err := s.finalize(pstmt); err != nil { 525 | return nil, err 526 | } 527 | 528 | return nil, fmt.Errorf("query contains multiple select statements") 529 | } 530 | 531 | rowStmt = pstmt 532 | rc0 = rc 533 | case bin.XSQLITE_DONE: 534 | if rowStmt == nil { 535 | rc0 = rc 536 | } 537 | default: 538 | err = s.errstr(int32(rc)) 539 | s.finalize(pstmt) 540 | return nil, err 541 | } 542 | } 543 | return newRows(s, rowStmt, rc0) 544 | } 545 | 546 | // int sqlite3_bind_double(sqlite3_stmt*, int, double); 547 | func (s *stmt) bindDouble(pstmt unsafe.Pointer, idx1 int, value float64) (err error) { 548 | if rc := bin.Xsqlite3_bind_double(s.tls, pstmt, int32(idx1), value); rc != 0 { 549 | return s.errstr(rc) 550 | } 551 | 552 | return nil 553 | } 554 | 555 | // int sqlite3_bind_int(sqlite3_stmt*, int, int); 556 | func (s *stmt) bindInt(pstmt unsafe.Pointer, idx1, value int) (err error) { 557 | if rc := bin.Xsqlite3_bind_int(s.tls, pstmt, int32(idx1), int32(value)); rc != bin.XSQLITE_OK { 558 | return s.errstr(rc) 559 | } 560 | 561 | return nil 562 | } 563 | 564 | // int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); 565 | func (s *stmt) bindInt64(pstmt unsafe.Pointer, idx1 int, value int64) (err error) { 566 | if rc := bin.Xsqlite3_bind_int64(s.tls, pstmt, int32(idx1), value); rc != bin.XSQLITE_OK { 567 | return s.errstr(rc) 568 | } 569 | 570 | return nil 571 | } 572 | 573 | // int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); 574 | func (s *stmt) bindBlob(pstmt unsafe.Pointer, idx1 int, value []byte) (err error) { 575 | p, err := s.malloc(len(value)) 576 | if err != nil { 577 | return err 578 | } 579 | 580 | s.allocs = append(s.allocs, p) 581 | crt.CopyBytes(p, value, false) 582 | if rc := bin.Xsqlite3_bind_blob(s.tls, pstmt, int32(idx1), p, int32(len(value)), nil); rc != bin.XSQLITE_OK { 583 | return s.errstr(rc) 584 | } 585 | 586 | return nil 587 | } 588 | 589 | // int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); 590 | func (s *stmt) bindText(pstmt unsafe.Pointer, idx1 int, value string) (err error) { 591 | p, err := s.cString(value) 592 | if err != nil { 593 | return err 594 | } 595 | 596 | s.allocs = append(s.allocs, unsafe.Pointer(p)) 597 | if rc := bin.Xsqlite3_bind_text(s.tls, pstmt, int32(idx1), p, int32(len(value)), nil); rc != bin.XSQLITE_OK { 598 | return s.errstr(rc) 599 | } 600 | 601 | return nil 602 | } 603 | 604 | func (s *stmt) bind(pstmt unsafe.Pointer, n int, args []namedValue) error { 605 | for i := 1; i <= n; i++ { 606 | name, err := s.bindParameterName(pstmt, i) 607 | if err != nil { 608 | return err 609 | } 610 | 611 | var v namedValue 612 | for _, v = range args { 613 | if name != "" { 614 | // sqlite supports '$', '@' and ':' prefixes for string 615 | // identifiers and '?' for numeric, so we cannot 616 | // combine different prefixes with the same name 617 | // because `database/sql` requires variable names 618 | // to start with a letter 619 | if name[1:] == v.Name[:] { 620 | break 621 | } 622 | } else { 623 | if v.Ordinal == i { 624 | break 625 | } 626 | } 627 | } 628 | 629 | if v.Ordinal == 0 { 630 | if name != "" { 631 | return fmt.Errorf("missing named argument %q", name[1:]) 632 | } 633 | 634 | return fmt.Errorf("missing argument with %d index", i) 635 | } 636 | 637 | switch x := v.Value.(type) { 638 | case int64: 639 | if err := s.bindInt64(pstmt, i, x); err != nil { 640 | return err 641 | } 642 | case float64: 643 | if err := s.bindDouble(pstmt, i, x); err != nil { 644 | return err 645 | } 646 | case bool: 647 | v := 0 648 | if x { 649 | v = 1 650 | } 651 | if err := s.bindInt(pstmt, i, v); err != nil { 652 | return err 653 | } 654 | case []byte: 655 | if err := s.bindBlob(pstmt, i, x); err != nil { 656 | return err 657 | } 658 | case string: 659 | if err := s.bindText(pstmt, i, x); err != nil { 660 | return err 661 | } 662 | case time.Time: 663 | if err := s.bindText(pstmt, i, x.String()); err != nil { 664 | return err 665 | } 666 | default: 667 | return fmt.Errorf("invalid driver.Value type %T", x) 668 | } 669 | } 670 | return nil 671 | } 672 | 673 | // int sqlite3_bind_parameter_count(sqlite3_stmt*); 674 | func (s *stmt) bindParameterCount(pstmt unsafe.Pointer) (_ int, err error) { 675 | r := bin.Xsqlite3_bind_parameter_count(s.tls, pstmt) 676 | return int(r), nil 677 | } 678 | 679 | // const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); 680 | func (s *stmt) bindParameterName(pstmt unsafe.Pointer, i int) (string, error) { 681 | p := bin.Xsqlite3_bind_parameter_name(s.tls, pstmt, int32(i)) 682 | return crt.GoString(p), nil 683 | } 684 | 685 | // int sqlite3_finalize(sqlite3_stmt *pStmt); 686 | func (s *stmt) finalize(pstmt unsafe.Pointer) error { 687 | if rc := bin.Xsqlite3_finalize(s.tls, pstmt); rc != bin.XSQLITE_OK { 688 | return s.errstr(rc) 689 | } 690 | 691 | return nil 692 | } 693 | 694 | // int sqlite3_step(sqlite3_stmt*); 695 | func (s *stmt) step(pstmt unsafe.Pointer) (int, error) { 696 | r := bin.Xsqlite3_step(s.tls, pstmt) 697 | return int(r), nil 698 | } 699 | 700 | // int sqlite3_prepare_v2( 701 | // sqlite3 *db, /* Database handle */ 702 | // const char *zSql, /* SQL statement, UTF-8 encoded */ 703 | // int nByte, /* Maximum length of zSql in bytes. */ 704 | // sqlite3_stmt **ppStmt, /* OUT: Statement handle */ 705 | // const char **pzTail /* OUT: Pointer to unused portion of zSql */ 706 | // ); 707 | func (s *stmt) prepareV2(zSQL *int8) error { 708 | if rc := bin.Xsqlite3_prepare_v2(s.tls, s.pdb(), zSQL, -1, s.ppstmt, s.pzTail); rc != bin.XSQLITE_OK { 709 | return s.errstr(rc) 710 | } 711 | 712 | return nil 713 | } 714 | 715 | type tx struct { 716 | *conn 717 | } 718 | 719 | func (t *tx) String() string { return fmt.Sprintf("&%T@%p{conn: %p}", *t, t, t.conn) } 720 | 721 | func newTx(c *conn) (*tx, error) { 722 | t := &tx{conn: c} 723 | if err := t.exec(context.Background(), "begin"); err != nil { 724 | return nil, err 725 | } 726 | 727 | return t, nil 728 | } 729 | 730 | // Commit implements driver.Tx. 731 | func (t *tx) Commit() (err error) { 732 | if trace { 733 | defer func() { 734 | tracer(t, "Commit(): %v", err) 735 | }() 736 | } 737 | return t.exec(context.Background(), "commit") 738 | } 739 | 740 | // Rollback implements driver.Tx. 741 | func (t *tx) Rollback() (err error) { 742 | if trace { 743 | defer func() { 744 | tracer(t, "Rollback(): %v", err) 745 | }() 746 | } 747 | return t.exec(context.Background(), "rollback") 748 | } 749 | 750 | // int sqlite3_exec( 751 | // sqlite3*, /* An open database */ 752 | // const char *sql, /* SQL to be evaluated */ 753 | // int (*callback)(void*,int,char**,char**), /* Callback function */ 754 | // void *, /* 1st argument to callback */ 755 | // char **errmsg /* Error msg written here */ 756 | // ); 757 | func (t *tx) exec(ctx context.Context, sql string) (err error) { 758 | psql, err := t.cString(sql) 759 | if err != nil { 760 | return err 761 | } 762 | 763 | defer t.free(unsafe.Pointer(psql)) 764 | 765 | // TODO: use t.conn.ExecContext() instead 766 | donech := make(chan struct{}) 767 | defer close(donech) 768 | go func() { 769 | select { 770 | case <-ctx.Done(): 771 | t.interrupt(t.pdb()) 772 | case <-donech: 773 | } 774 | }() 775 | 776 | if rc := bin.Xsqlite3_exec(t.tls, t.pdb(), psql, nil, nil, nil); rc != bin.XSQLITE_OK { 777 | return t.errstr(rc) 778 | } 779 | 780 | return nil 781 | } 782 | 783 | type conn struct { 784 | *Driver 785 | ppdb **bin.Xsqlite3 786 | tls *crt.TLS 787 | } 788 | 789 | func (c *conn) String() string { 790 | return fmt.Sprintf("&%T@%p{sqlite: %p, Thread: %p, ppdb: %#x}", *c, c, c.Driver, c.tls, c.ppdb) 791 | } 792 | 793 | func newConn(s *Driver, name string) (_ *conn, err error) { 794 | c := &conn{Driver: s} 795 | 796 | defer func() { 797 | if err != nil { 798 | c.close() 799 | } 800 | }() 801 | 802 | c.Lock() 803 | 804 | defer c.Unlock() 805 | 806 | c.tls = crt.NewTLS() 807 | if err = c.openV2( 808 | name, 809 | bin.XSQLITE_OPEN_READWRITE|bin.XSQLITE_OPEN_CREATE| 810 | bin.XSQLITE_OPEN_FULLMUTEX| 811 | bin.XSQLITE_OPEN_URI, 812 | ); err != nil { 813 | return nil, err 814 | } 815 | 816 | if err = c.extendedResultCodes(true); err != nil { 817 | return nil, err 818 | } 819 | 820 | return c, nil 821 | } 822 | 823 | // Prepare returns a prepared statement, bound to this connection. 824 | func (c *conn) Prepare(query string) (s driver.Stmt, err error) { 825 | return c.prepare(context.Background(), query) 826 | } 827 | 828 | func (c *conn) prepare(ctx context.Context, query string) (s driver.Stmt, err error) { 829 | if trace { 830 | defer func() { 831 | tracer(c, "Prepare(%s): (%v, %v)", query, s, err) 832 | }() 833 | } 834 | return newStmt(c, query) 835 | } 836 | 837 | // Close invalidates and potentially stops any current prepared statements and 838 | // transactions, marking this connection as no longer in use. 839 | // 840 | // Because the sql package maintains a free pool of connections and only calls 841 | // Close when there's a surplus of idle connections, it shouldn't be necessary 842 | // for drivers to do their own connection caching. 843 | func (c *conn) Close() (err error) { 844 | if trace { 845 | defer func() { 846 | tracer(c, "Close(): %v", err) 847 | }() 848 | } 849 | return c.close() 850 | } 851 | 852 | // Begin starts a transaction. 853 | func (c *conn) Begin() (driver.Tx, error) { 854 | return c.begin(context.Background(), txOptions{}) 855 | } 856 | 857 | // copy of driver.TxOptions 858 | type txOptions struct { 859 | Isolation int // driver.IsolationLevel 860 | ReadOnly bool 861 | } 862 | 863 | func (c *conn) begin(ctx context.Context, opts txOptions) (t driver.Tx, err error) { 864 | if trace { 865 | defer func() { 866 | tracer(c, "BeginTx(): (%v, %v)", t, err) 867 | }() 868 | } 869 | return newTx(c) 870 | } 871 | 872 | // Execer is an optional interface that may be implemented by a Conn. 873 | // 874 | // If a Conn does not implement Execer, the sql package's DB.Exec will first 875 | // prepare a query, execute the statement, and then close the statement. 876 | // 877 | // Exec may return ErrSkip. 878 | func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) { 879 | return c.exec(context.Background(), query, toNamedValues(args)) 880 | } 881 | 882 | func (c *conn) exec(ctx context.Context, query string, args []namedValue) (r driver.Result, err error) { 883 | if trace { 884 | defer func() { 885 | tracer(c, "ExecContext(%s, %v): (%v, %v)", query, args, r, err) 886 | }() 887 | } 888 | 889 | s, err := c.prepare(ctx, query) 890 | if err != nil { 891 | return nil, err 892 | } 893 | 894 | defer func() { 895 | if err2 := s.Close(); err2 != nil && err == nil { 896 | err = err2 897 | } 898 | }() 899 | 900 | return s.(*stmt).exec(ctx, args) 901 | } 902 | 903 | // copy of driver.NameValue 904 | type namedValue struct { 905 | Name string 906 | Ordinal int 907 | Value driver.Value 908 | } 909 | 910 | // toNamedValues converts []driver.Value to []namedValue 911 | func toNamedValues(vals []driver.Value) []namedValue { 912 | args := make([]namedValue, 0, len(vals)) 913 | for i, val := range vals { 914 | args = append(args, namedValue{Value: val, Ordinal: i + 1}) 915 | } 916 | return args 917 | } 918 | 919 | // Queryer is an optional interface that may be implemented by a Conn. 920 | // 921 | // If a Conn does not implement Queryer, the sql package's DB.Query will first 922 | // prepare a query, execute the statement, and then close the statement. 923 | // 924 | // Query may return ErrSkip. 925 | func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) { 926 | return c.query(context.Background(), query, toNamedValues(args)) 927 | } 928 | 929 | func (c *conn) query(ctx context.Context, query string, args []namedValue) (r driver.Rows, err error) { 930 | if trace { 931 | defer func() { 932 | tracer(c, "Query(%s, %v): (%v, %v)", query, args, r, err) 933 | }() 934 | } 935 | s, err := c.prepare(ctx, query) 936 | if err != nil { 937 | return nil, err 938 | } 939 | 940 | defer func() { 941 | if err2 := s.Close(); err2 != nil && err == nil { 942 | err = err2 943 | } 944 | }() 945 | 946 | return s.(*stmt).query(ctx, args) 947 | } 948 | 949 | func (c *conn) pdb() *bin.Xsqlite3 { return *c.ppdb } 950 | 951 | // int sqlite3_extended_result_codes(sqlite3*, int onoff); 952 | func (c *conn) extendedResultCodes(on bool) (err error) { 953 | var v int32 954 | if on { 955 | v = 1 956 | } 957 | if rc := bin.Xsqlite3_extended_result_codes(c.tls, c.pdb(), v); rc != bin.XSQLITE_OK { 958 | return c.errstr(rc) 959 | } 960 | 961 | return nil 962 | } 963 | 964 | // void *sqlite3_malloc(int); 965 | func (c *conn) malloc(n int) (r unsafe.Pointer, err error) { 966 | if n > math.MaxInt32 { 967 | panic("internal error") 968 | } 969 | 970 | r = bin.Xsqlite3_malloc(c.tls, int32(n)) 971 | if r == nil { 972 | return nil, fmt.Errorf("malloc(%v) failed", n) 973 | } 974 | 975 | return r, nil 976 | } 977 | 978 | func (c *conn) cString(s string) (*int8, error) { 979 | n := len(s) 980 | p, err := c.malloc(n + 1) 981 | if err != nil { 982 | return nil, err 983 | } 984 | 985 | crt.CopyString(p, s, true) 986 | return (*int8)(p), nil 987 | } 988 | 989 | // int sqlite3_open_v2( 990 | // const char *filename, /* Database filename (UTF-8) */ 991 | // sqlite3 **ppDb, /* OUT: SQLite db handle */ 992 | // int flags, /* Flags */ 993 | // const char *zVfs /* Name of VFS module to use */ 994 | // ); 995 | func (c *conn) openV2(name string, flags int32) error { 996 | filename, err := c.cString(name) 997 | if err != nil { 998 | return err 999 | } 1000 | 1001 | defer c.free(unsafe.Pointer(filename)) 1002 | 1003 | ppdb, err := c.malloc(ptrSize) 1004 | if err != nil { 1005 | return err 1006 | } 1007 | 1008 | c.ppdb = (**bin.Xsqlite3)(ppdb) 1009 | if rc := bin.Xsqlite3_open_v2(c.tls, filename, c.ppdb, flags, nil); rc != bin.XSQLITE_OK { 1010 | return c.errstr(rc) 1011 | } 1012 | 1013 | return nil 1014 | } 1015 | 1016 | // const char *sqlite3_errstr(int); 1017 | func (c *conn) errstr(rc int32) (err error) { 1018 | p := bin.Xsqlite3_errstr(c.tls, rc) 1019 | str := crt.GoString(p) 1020 | p = bin.Xsqlite3_errmsg(c.tls, c.pdb()) 1021 | 1022 | switch msg := crt.GoString(p); { 1023 | case msg == str: 1024 | return fmt.Errorf("%s (%v)", str, rc) 1025 | default: 1026 | return fmt.Errorf("%s: %s (%v)", str, msg, rc) 1027 | } 1028 | } 1029 | 1030 | // int sqlite3_close_v2(sqlite3*); 1031 | func (c *conn) closeV2() (err error) { 1032 | if rc := bin.Xsqlite3_close_v2(c.tls, c.pdb()); rc != bin.XSQLITE_OK { 1033 | return c.errstr(rc) 1034 | } 1035 | 1036 | err = c.free(unsafe.Pointer(c.ppdb)) 1037 | c.ppdb = nil 1038 | return err 1039 | } 1040 | 1041 | // void sqlite3_free(void*); 1042 | func (c *conn) free(p unsafe.Pointer) (err error) { 1043 | bin.Xsqlite3_free(c.tls, p) 1044 | return nil 1045 | } 1046 | 1047 | // void sqlite3_interrupt(sqlite3*); 1048 | func (c *conn) interrupt(pdb *bin.Xsqlite3) (err error) { 1049 | bin.Xsqlite3_interrupt(c.tls, pdb) 1050 | return nil 1051 | } 1052 | 1053 | func (c *conn) close() (err error) { 1054 | c.Lock() 1055 | 1056 | defer c.Unlock() 1057 | 1058 | if c.ppdb != nil { 1059 | err = c.closeV2() 1060 | } 1061 | return err 1062 | } 1063 | 1064 | // Driver implements database/sql/driver.Driver. 1065 | type Driver struct { 1066 | sync.Mutex 1067 | } 1068 | 1069 | func newDrv() *Driver { return &Driver{} } 1070 | 1071 | // Open returns a new connection to the database. The name is a string in a 1072 | // driver-specific format. 1073 | // 1074 | // Open may return a cached connection (one previously closed), but doing so is 1075 | // unnecessary; the sql package maintains a pool of idle connections for 1076 | // efficient re-use. 1077 | // 1078 | // The returned connection is only used by one goroutine at a time. 1079 | func (s *Driver) Open(name string) (c driver.Conn, err error) { 1080 | if trace { 1081 | defer func() { 1082 | tracer(s, "Open(%s): (%v, %v)", name, c, err) 1083 | }() 1084 | } 1085 | return newConn(s, name) 1086 | } 1087 | --------------------------------------------------------------------------------