Commit c889fbc9 authored by gwenn's avatar gwenn

Introduce Conn#Filename and Conn#Readonly.

parent ca2fb674
......@@ -3,6 +3,8 @@ Yet another SQLite binding based on:
- the [Patrick Crosby's](https://github.com/patrickxb/fgosqlite/) fork.
This binding implements the "database/sql/driver" interface.
See [package documentation](http://go.pkgdoc.org/github.com/gwenn/gosqlite).
Open supports flags.
Conn#Exec handles multiple statements (separated by semicolons) properly.
Conn#Prepare can optionnaly #Bind as well.
......@@ -44,7 +46,7 @@ Conn#GetAutocommit
Conn#EnableLoadExtension/LoadExtension
Conn#IntegrityCheck
Stmt#Insert/ExecDml/Select
Stmt#Insert/ExecDml/Select/SelectOneRow
Stmt#BindParameterCount/BindParameterIndex(name)/BindParameterName(index)
Stmt#ClearBindings
Stmt#ColumnCount/ColumnNames/ColumnIndex(name)/ColumnName(index)/ColumnType(index)
......
......@@ -24,7 +24,7 @@ func fill(db *Conn, n int) {
func BenchmarkValuesScan(b *testing.B) {
b.StopTimer()
db, _ := Open("")
db, _ := Open(":memory:")
defer db.Close()
fill(db, 1)
......@@ -44,7 +44,7 @@ func BenchmarkValuesScan(b *testing.B) {
func BenchmarkScan(b *testing.B) {
b.StopTimer()
db, _ := Open("")
db, _ := Open(":memory:")
defer db.Close()
fill(db, 1)
......@@ -67,7 +67,7 @@ func BenchmarkScan(b *testing.B) {
func BenchmarkNamedScan(b *testing.B) {
b.StopTimer()
db, _ := Open("")
db, _ := Open(":memory:")
defer db.Close()
fill(db, 1)
......@@ -89,13 +89,13 @@ func BenchmarkNamedScan(b *testing.B) {
}
func BenchmarkInsert(b *testing.B) {
db, _ := Open("")
db, _ := Open(":memory:")
defer db.Close()
fill(db, b.N)
}
func BenchmarkNamedInsert(b *testing.B) {
db, _ := Open("")
db, _ := Open(":memory:")
defer db.Close()
db.Exec("DROP TABLE IF EXISTS test")
db.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL," +
......
......@@ -63,7 +63,7 @@ func TestEnabledCache(t *testing.T) {
}
func BenchmarkDisabledCache(b *testing.B) {
db, _ := Open("")
db, _ := Open(":memory:")
defer db.Close()
db.SetCacheSize(0)
......@@ -79,7 +79,7 @@ func BenchmarkDisabledCache(b *testing.B) {
}
func BenchmarkEnabledCache(b *testing.B) {
db, _ := Open("")
db, _ := Open(":memory:")
defer db.Close()
db.SetCacheSize(10)
......
......@@ -22,7 +22,7 @@ const (
)
func sqlOpen(t *testing.T) *sql.DB {
db, err := sql.Open("sqlite3", "")
db, err := sql.Open("sqlite3", ":memory:")
checkNoError(t, err, "Error opening database: %s")
return db
}
......
......@@ -16,7 +16,7 @@ func check(err error) {
}
func Example() {
db, err := sqlite.Open("") // path to db or "" for temp db
db, err := sqlite.Open(":memory:") // path to db or "" for temp db
check(err)
defer db.Close()
err = db.Exec("CREATE TABLE test(id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL UNIQUE); -- ... and other ddls separated by semi-colon")
......@@ -44,12 +44,12 @@ func ExampleOpen() {
db, err := sqlite.Open(":memory:")
check(err)
defer db.Close()
fmt.Printf("db path: %q\n", db.Filename)
// Output: db path: ":memory:"
fmt.Printf("db path: %q\n", db.Filename("main"))
// Output: db path: ""
}
func ExampleConn_Exec() {
db, err := sqlite.Open("")
db, err := sqlite.Open(":memory:")
check(err)
defer db.Close()
......@@ -62,7 +62,7 @@ func ExampleConn_Exec() {
}
func ExampleStmt_ExecDml() {
db, err := sqlite.Open("")
db, err := sqlite.Open(":memory:")
check(err)
defer db.Close()
err = db.Exec("CREATE TABLE test (content TEXT); INSERT INTO test VALUES ('Go'); INSERT INTO test VALUES ('SQLite')")
......@@ -78,7 +78,7 @@ func ExampleStmt_ExecDml() {
}
func ExampleStmt_Insert() {
db, err := sqlite.Open("")
db, err := sqlite.Open(":memory:")
check(err)
defer db.Close()
err = db.Exec("CREATE TABLE test (content TEXT)")
......@@ -99,7 +99,7 @@ func ExampleStmt_Insert() {
}
func ExampleStmt_NamedScan() {
db, err := sqlite.Open("")
db, err := sqlite.Open(":memory:")
check(err)
defer db.Close()
......@@ -121,7 +121,7 @@ func ExampleStmt_NamedScan() {
}
func ExampleStmt_Scan() {
db, err := sqlite.Open("")
db, err := sqlite.Open(":memory:")
check(err)
defer db.Close()
......@@ -143,10 +143,10 @@ func ExampleStmt_Scan() {
}
func ExampleNewBackup() {
dst, err := sqlite.Open("")
dst, err := sqlite.Open(":memory:")
check(err)
defer dst.Close()
src, err := sqlite.Open("")
src, err := sqlite.Open(":memory:")
check(err)
defer src.Close()
err = src.Exec("CREATE TABLE test (content BLOB); INSERT INTO test VALUES (zeroblob(100))")
......@@ -172,7 +172,7 @@ func ExampleNewBackup() {
}
func ExampleConn_NewBlobReader() {
db, err := sqlite.Open("")
db, err := sqlite.Open(":memory:")
check(err)
err = db.Exec("CREATE TABLE test (content BLOB); INSERT INTO test VALUES (zeroblob(10))")
check(err)
......
......@@ -21,10 +21,9 @@ func half(ctx *ScalarContext, nArg int) {
}
func TestScalarFunction(t *testing.T) {
db, err := Open("")
checkNoError(t, err, "couldn't open database file: %s")
db := open(t)
defer db.Close()
err = db.CreateScalarFunction("half", 1, nil, half, nil)
err := db.CreateScalarFunction("half", 1, nil, half, nil)
checkNoError(t, err, "couldn't create function: %s")
var d float64
err = db.OneValue("select half(6)", &d)
......@@ -69,10 +68,9 @@ func reDestroy(ad interface{}) {
}
func TestRegexpFunction(t *testing.T) {
db, err := Open("")
checkNoError(t, err, "couldn't open database file: %s")
db := open(t)
defer db.Close()
err = db.CreateScalarFunction("regexp", 2, nil, re, reDestroy)
err := db.CreateScalarFunction("regexp", 2, nil, re, reDestroy)
checkNoError(t, err, "couldn't create function: %s")
s, err := db.Prepare("select regexp('l.s[aeiouy]', name) from (select 'lisa' as name union all select 'bart')")
checkNoError(t, err, "couldn't prepare statement: %s")
......@@ -117,10 +115,9 @@ func sumFinal(ctx *AggregateContext) {
}
func TestSumFunction(t *testing.T) {
db, err := Open("")
checkNoError(t, err, "couldn't open database file: %s")
db := open(t)
defer db.Close()
err = db.CreateAggregateFunction("mysum", 1, nil, sumStep, sumFinal, nil)
err := db.CreateAggregateFunction("mysum", 1, nil, sumStep, sumFinal, nil)
checkNoError(t, err, "couldn't create function: %s")
var i int
err = db.OneValue("select mysum(i) from (select 2 as i union all select 2)", &i)
......@@ -145,7 +142,7 @@ func randomFill(db *Conn, n int) {
func BenchmarkLike(b *testing.B) {
b.StopTimer()
db, _ := Open("")
db, _ := Open(":memory:")
defer db.Close()
randomFill(db, 1)
cs, _ := db.Prepare("SELECT count(1) FROM test where name like 'lisa'")
......@@ -160,7 +157,7 @@ func BenchmarkLike(b *testing.B) {
func BenchmarkHalf(b *testing.B) {
b.StopTimer()
db, _ := Open("")
db, _ := Open(":memory:")
defer db.Close()
randomFill(db, 1)
db.CreateScalarFunction("half", 1, nil, half, nil)
......@@ -176,7 +173,7 @@ func BenchmarkHalf(b *testing.B) {
func BenchmarkRegexp(b *testing.B) {
b.StopTimer()
db, _ := Open("")
db, _ := Open(":memory:")
defer db.Close()
randomFill(db, 1)
db.CreateScalarFunction("regexp", 2, nil, re, reDestroy)
......
......@@ -43,7 +43,7 @@ func (e *ConnError) ExtendedCode() int {
// Return Database file name from which the error comes from.
func (e *ConnError) Filename() string {
return e.c.Filename
return e.c.Filename("main")
}
func (e *ConnError) Error() string { // FIXME code.Error() & e.msg are often redundant...
......@@ -158,7 +158,6 @@ func (c *Conn) LastError() error {
// Database connection handle
type Conn struct {
db *C.sqlite3
Filename string
stmtCache *cache
authorizer *sqliteAuthorizer
busyHandler *sqliteBusyHandler
......@@ -233,7 +232,7 @@ func OpenVfs(filename string, vfsname string, flags ...OpenFlag) (*Conn, error)
if db == nil {
return nil, errors.New("sqlite succeeded without returning a database")
}
return &Conn{db: db, Filename: filename, stmtCache: newCache()}, nil
return &Conn{db: db, stmtCache: newCache()}, nil
}
// Set a busy timeout
......@@ -273,6 +272,24 @@ func (c *Conn) EnableExtendedResultCodes(b bool) error {
return c.error(C.sqlite3_extended_result_codes(c.db, btocint(b)))
}
// (See http://sqlite.org/c3ref/db_readonly.html)
func (c *Conn) Readonly(dbName string) (bool, error) {
cname := C.CString(dbName)
defer C.free(unsafe.Pointer(cname))
rv := C.sqlite3_db_readonly(c.db, cname)
if rv == -1 {
return false, c.error(C.SQLITE_ERROR, fmt.Sprintf("%q is not the name of a database", dbName))
}
return rv == 1, nil
}
// (See http://sqlite.org/c3ref/db_filename.html)
func (c *Conn) Filename(dbName string) string {
cname := C.CString(dbName)
defer C.free(unsafe.Pointer(cname))
return C.GoString(C.sqlite3_db_filename(c.db, cname))
}
// Prepare and execute one parameterized statement or many statements (separated by semi-colon).
// Don't use it with SELECT or anything that returns data.
func (c *Conn) Exec(cmd string, args ...interface{}) error {
......
......@@ -18,7 +18,7 @@ func checkNoError(t *testing.T, err error, format string) {
}
func open(t *testing.T) *Conn {
db, err := Open("", OPEN_READWRITE, OPEN_CREATE, OPEN_FULLMUTEX)
db, err := Open(":memory:", OPEN_READWRITE, OPEN_CREATE, OPEN_FULLMUTEX)
checkNoError(t, err, "couldn't open database file: %s")
if db == nil {
t.Fatal("opened database is nil")
......
......@@ -70,8 +70,7 @@ func updateHook(d interface{}, a Action, dbName, tableName string, rowId int64)
}
func TestNoTrace(t *testing.T) {
db, err := Open("")
checkNoError(t, err, "couldn't open database: %s")
db := open(t)
defer db.Close()
db.Trace(nil, nil)
db.SetAuthorizer(nil, nil)
......@@ -84,11 +83,10 @@ func TestNoTrace(t *testing.T) {
}
func TestTrace(t *testing.T) {
db, err := Open("")
checkNoError(t, err, "couldn't open database: %s")
db := open(t)
defer db.Close()
db.Trace(trace, t)
err = db.SetAuthorizer(authorizer, t)
err := db.SetAuthorizer(authorizer, t)
checkNoError(t, err, "couldn't set an authorizer")
db.Profile(profile, t)
db.ProgressHandler(progressHandler, 1, t)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment