Commit 7453f923 authored by gwenn's avatar gwenn

Introduce OneValue helper.

parent 72cf0e47
Yet another SQLite binding based on:
- original [Russ Cox's](http://code.google.com/p/gosqlite/) implementation,
- the [Patrick Crosby's](https://github.com/patrickxb/fgosqlite/) fork.
This binding implements the "exp/sql/driver" interface but leaves dangling statements (see drivert_test).
Open supports flags.
Conn#Exec handles multiple statements (separated by semicolons) properly.
......@@ -8,9 +9,10 @@ Conn#Prepare can optionnaly #Bind as well.
Conn#Close ensures that all dangling statements are finalized.
Stmt#Exec is renamed in Stmt#Bind and a new Stmt#Exec method is introduced to #Bind and #Step.
Stmt#Bind uses native sqlite3_bind_x methods and failed if unsupported type.
Stmt#NamedBind can be used to bind by name.
Stmt#Next returns a (bool, os.Error) couple like Reader#Read.
Stmt#Scan uses native sqlite3_column_x methods.
Stmt#NamedScan is added. It's compliant with [go-dbi](https://github.com/thomaslee/go-dbi/) API but I think its signature should be improved/modified.
Stmt#NamedScan is added. It's compliant with [go-dbi](https://github.com/thomaslee/go-dbi/).
Stmt#ScanByIndex/ScanByName are added to test NULL value.
Currently, the weak point of the binding is the *Scan methods:
......@@ -26,6 +28,10 @@ Using the native sqlite3_column_x implies:
Maybe we should let the caller do the conversion.
Misc:
Conn#Exists
Conn#OneValue
Conn#OpenVfs
Conn#EnableFkey/IsFKeyEnabled
Conn#Changes/TotalChanges
Conn#LastInsertRowid
......@@ -33,8 +39,9 @@ Conn#Interrupt
Conn#Begin/BeginTransaction(type)/Commit/Rollback
Conn#GetAutocommit
Conn#EnableLoadExtension/LoadExtension
Conn#IntegrityCheck
Stmt#ExecUpdate
Stmt#ExecInsert/ExecUpdate
Stmt#BindParameterCount/BindParameterIndex/BindParameterName
Stmt#ClearBindings
Stmt#ColumnCount/ColumnNames/ColumnIndex(name)/ColumnName(index)/ColumnType(index)
......@@ -64,3 +71,8 @@ Conn#ProgressHandler
Conn#SetAuthorizer
Conn#Trace
Stmt#Status
Hook:
Conn#CommitHook
Conn#RollbackHook
Conn#UpdateHook
......@@ -24,22 +24,12 @@ func TestScalarFunction(t *testing.T) {
if err = db.CreateScalarFunction("half", 1, nil, half, nil); err != nil {
t.Fatalf("couldn't create function: %s", err)
}
s, err := db.Prepare("select half(6)")
d, err := db.OneValue("select half(6)")
if err != nil {
t.Fatalf("couldn't prepare statement: %s", err)
}
if b := Must(s.Next()); !b {
t.Fatalf("No result")
}
d, _, err := s.ScanDouble(0)
if err != nil {
t.Fatalf("couldn't scan result: %s", err)
}
if d != 3 {
t.Errorf("Expected %f but got %f", 3, d)
t.Fatalf("couldn't retrieve result: %s", err)
}
if err = s.Finalize(); err != nil {
t.Fatalf("couldn't finalize statement: %s", err)
if d != 3.0 {
t.Errorf("Expected %f but got %f", 3.0, d)
}
if err = db.CreateScalarFunction("half", 1, nil, nil, nil); err != nil {
t.Errorf("couldn't destroy function: %s", err)
......
......@@ -37,6 +37,7 @@ import "C"
import (
"errors"
"fmt"
"io"
"reflect"
"unsafe"
)
......@@ -373,6 +374,23 @@ func (c *Conn) Exists(query string, args ...interface{}) (bool, error) {
return s.Next()
}
// Use it with SELECT that returns only one row with only one column.
// Returns io.EOF when there is no row.
func (c *Conn) OneValue(query string, args ...interface{}) (interface{}, error) {
s, err := c.Prepare(query, args...)
if err != nil {
return nil, err
}
defer s.Finalize()
b, err := s.Next()
if err != nil {
return nil, err
} else if !b {
return nil, io.EOF
}
return s.ScanValue(0), nil
}
// Count the number of rows modified
// Calls http://sqlite.org/c3ref/changes.html
func (c *Conn) Changes() int {
......@@ -872,6 +890,7 @@ func (s *Stmt) ScanByName(name string, value interface{}) (bool, error) {
// The leftmost column/index is number 0.
//
// Destination type is specified by the caller.
// The value must be of one of the following types:
// *string
// *int, *int64, *byte,
......@@ -912,7 +931,8 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (bool, error) {
}
// The leftmost column/index is number 0.
//
//
// Destination type is decided by SQLite.
// The returned value will be of one of the following types:
// nil
// string
......@@ -1193,20 +1213,10 @@ func (c *Conn) IntegrityCheck(max int, quick bool) error {
} else {
pragma = "integrity"
}
s, err := c.Prepare(fmt.Sprintf("PRAGMA %s_check(%d)", pragma, max))
msg, err := c.OneValue(fmt.Sprintf("PRAGMA %s_check(%d)", pragma, max))
if err != nil {
return err
}
defer s.Finalize()
if ok, err := s.Next(); err != nil {
return err
} else if !ok {
return c.specificError("Integrity check failed (no result)")
}
msg, null := s.ScanText(0)
if null {
return c.specificError("Integrity check failed (null result)")
}
if msg != "ok" {
return c.specificError("Integrity check failed (%s)", msg)
}
......
......@@ -166,7 +166,7 @@ func TestInsertWithStatement(t *testing.T) {
defer s.Finalize()
if s.ReadOnly() {
t.Errorf("update statement is not readonly")
t.Errorf("update statement should not be readonly")
}
paramCount := s.BindParameterCount()
......@@ -200,7 +200,7 @@ func TestInsertWithStatement(t *testing.T) {
cs, _ := db.Prepare("SELECT COUNT(*) FROM test")
defer cs.Finalize()
if !cs.ReadOnly() {
t.Errorf("update statement is not readonly")
t.Errorf("select statement should be readonly")
}
if !Must(cs.Next()) {
t.Fatal("no result for count")
......
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