Commit 6b4ec960 authored by gwenn's avatar gwenn

Introduce ScanColumn and NamedScanColumn as the less ugly way (i can see) to known if

a column is null.
parent cbd9900c
......@@ -469,12 +469,12 @@ func (s *Stmt) NamedScan(args ...interface{}) os.Error {
if !ok {
return os.NewError("non-string field name field")
}
index, err := s.fieldIndex(name) // How to look up only once for one statement ?
index, err := s.ColumnIndex(name) // How to look up only once for one statement ?
if err != nil {
return err
}
ptr := args[i+1]
_, err = s.scanField(index, ptr, false)
_, err = s.ScanColumn(index, ptr, false)
if err != nil {
return err
}
......@@ -493,7 +493,7 @@ func (s *Stmt) Scan(args ...interface{}) os.Error {
}
for i, v := range args {
_, err := s.scanField(i, v, false)
_, err := s.ScanColumn(i, v, false)
if err != nil {
return err
}
......@@ -506,7 +506,10 @@ func (s *Stmt) SQL() string {
return C.GoString(C.sqlite3_sql(s.stmt))
}
func (s *Stmt) fieldIndex(name string) (int, os.Error) {
// Must scan all columns (but result is cached).
// Calls sqlite3_column_count, sqlite3_column_name
// http://sqlite.org/c3ref/column_name.html
func (s *Stmt) ColumnIndex(name string) (int, os.Error) {
if s.cols == nil {
count := s.ColumnCount()
s.cols = make(map[string]int, count)
......@@ -523,7 +526,23 @@ func (s *Stmt) fieldIndex(name string) (int, os.Error) {
// Set nullable to false to skip NULL type test.
// Returns true when nullable is true and field is null.
func (s *Stmt) scanField(index int, value interface{}, nullable bool) (bool, os.Error) {
// Calls sqlite3_column_count, sqlite3_column_name and sqlite3_column_(blob|double|int|int64|text) depending on args type.
// http://sqlite.org/c3ref/column_blob.html
func (s *Stmt) NamedScanColumn(name string, value interface{}, nullable bool) (bool, os.Error) {
index, err := s.ColumnIndex(name)
if err != nil {
return false, err
}
return s.ScanColumn(index, value, true)
}
// The leftmost column is number 0.
// Index starts at 0.
// Set nullable to false to skip NULL type test.
// Returns true when nullable is true and field is null.
// Calls sqlite3_column_(blob|double|int|int64|text) depending on args type.
// http://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ScanColumn(index int, value interface{}, nullable bool) (bool, os.Error) {
var isNull bool
switch value := value.(type) {
case *string:
......
......@@ -216,10 +216,10 @@ func TestInsertWithStatement(t *testing.T) {
t.Errorf("column name error: %s <> 'int_num'", secondColumnName)
}
var fnum float64
var inum int64
var sstr string
if ok, _ := rs.Next(); ok {
var fnum float64
var inum int64
var sstr string
rs.Scan(&fnum, &inum, &sstr)
if fnum != 0 {
t.Errorf("Expected 0 <> %f\n", fnum)
......@@ -376,6 +376,90 @@ func TestBlob(t *testing.T) {
br.Close()
}
func testScanColumn(t *testing.T) {
db := open(t)
defer db.Close()
s, err := db.Prepare("select 1, null, 0")
if err != nil {
t.Fatalf("prepare error: %s", err)
}
defer s.Finalize()
if ok, err := s.Next(); !ok {
if err != nil {
t.Fatalf("error preparing count: %s", err)
}
t.Fatal("no result for count")
}
var i1, i2, i3 int
null, err := s.ScanColumn(0, &i1, true)
if err != nil {
t.Errorf("scan error: %s\n", err)
} else if null {
t.Errorf("Expected not null value")
} else if i1 != 1 {
t.Errorf("Expected 1 <> %d\n", i1)
}
null, err = s.ScanColumn(1, &i2, true)
if err != nil {
t.Errorf("scan error: %s\n", err)
} else if !null {
t.Errorf("Expected null value")
} else if i2 != 0 {
t.Errorf("Expected 0 <> %d\n", i2)
}
null, err = s.ScanColumn(2, &i3, true)
if err != nil {
t.Errorf("scan error: %s\n", err)
} else if null {
t.Errorf("Expected not null value")
} else if i3 != 0 {
t.Errorf("Expected 0 <> %d\n", i3)
}
}
func testNamedScanColumn(t *testing.T) {
db := open(t)
defer db.Close()
s, err := db.Prepare("select 1 as i1, null as i2, 0 as i3")
if err != nil {
t.Fatalf("prepare error: %s", err)
}
defer s.Finalize()
if ok, err := s.Next(); !ok {
if err != nil {
t.Fatalf("error preparing count: %s", err)
}
t.Fatal("no result for count")
}
var i1, i2, i3 int
null, err := s.NamedScanColumn("i1", &i1, true)
if err != nil {
t.Errorf("scan error: %s\n", err)
} else if null {
t.Errorf("Expected not null value")
} else if i1 != 1 {
t.Errorf("Expected 1 <> %d\n", i1)
}
null, err = s.NamedScanColumn("i2", &i2, true)
if err != nil {
t.Errorf("scan error: %s\n", err)
} else if !null {
t.Errorf("Expected null value")
} else if i2 != 0 {
t.Errorf("Expected 0 <> %d\n", i2)
}
null, err = s.NamedScanColumn("i3", &i3, true)
if err != nil {
t.Errorf("scan error: %s\n", err)
} else if null {
t.Errorf("Expected not null value")
} else if i3 != 0 {
t.Errorf("Expected 0 <> %d\n", i3)
}
}
func BenchmarkScan(b *testing.B) {
b.StopTimer()
db, _ := Open("")
......
......@@ -223,9 +223,9 @@ func (c *Conn) ProgressHandler(f ProgressHandler, freq int, arg interface{}) {
type StmtStatus int
const (
STMTSTATUS_FULLSCAN_STEP StmtStatus = C.SQLITE_STMTSTATUS_FULLSCAN_STEP
STMTSTATUS_SORT StmtStatus = C.SQLITE_STMTSTATUS_SORT
STMTSTATUS_AUTOINDEX StmtStatus = C.SQLITE_STMTSTATUS_AUTOINDEX
STMTSTATUS_FULLSCAN_STEP StmtStatus = C.SQLITE_STMTSTATUS_FULLSCAN_STEP
STMTSTATUS_SORT StmtStatus = C.SQLITE_STMTSTATUS_SORT
STMTSTATUS_AUTOINDEX StmtStatus = C.SQLITE_STMTSTATUS_AUTOINDEX
)
// Calls http://sqlite.org/c3ref/stmt_status.html
......
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