Commit 62a31153 authored by gwenn's avatar gwenn

Introduce Stmt#Select method.

parent ee538ffb
...@@ -39,7 +39,7 @@ Conn#GetAutocommit ...@@ -39,7 +39,7 @@ Conn#GetAutocommit
Conn#EnableLoadExtension/LoadExtension Conn#EnableLoadExtension/LoadExtension
Conn#IntegrityCheck Conn#IntegrityCheck
Stmt#ExecInsert/ExecUpdate Stmt#Insert/ExecDml/Select
Stmt#BindParameterCount/BindParameterIndex(name)/BindParameterName(index) Stmt#BindParameterCount/BindParameterIndex(name)/BindParameterName(index)
Stmt#ClearBindings Stmt#ClearBindings
Stmt#ColumnCount/ColumnNames/ColumnIndex(name)/ColumnName(index)/ColumnType(index) Stmt#ColumnCount/ColumnNames/ColumnIndex(name)/ColumnName(index)/ColumnType(index)
......
...@@ -347,7 +347,7 @@ func goXAuxDataDestroy(ad unsafe.Pointer) { ...@@ -347,7 +347,7 @@ func goXAuxDataDestroy(ad unsafe.Pointer) {
if c != nil { if c != nil {
delete(contexts, c.sc) delete(contexts, c.sc)
} }
// fmt.Printf("Contexts: %v\n", contexts) // fmt.Printf("Contexts: %v\n", contexts)
} }
//export goXFunc //export goXFunc
...@@ -404,7 +404,7 @@ func goXFinal(scp, udfp unsafe.Pointer) { ...@@ -404,7 +404,7 @@ func goXFinal(scp, udfp unsafe.Pointer) {
udf.final(c) udf.final(c)
} }
} }
// fmt.Printf("Contexts: %v\n", contexts) // fmt.Printf("Contexts: %v\n", contexts)
} }
//export goXDestroy //export goXDestroy
......
...@@ -26,18 +26,16 @@ func (c *Conn) Databases() (map[string]string, error) { ...@@ -26,18 +26,16 @@ func (c *Conn) Databases() (map[string]string, error) {
defer s.Finalize() defer s.Finalize()
var databases map[string]string = make(map[string]string) var databases map[string]string = make(map[string]string)
var name, file string var name, file string
for { err = s.Select(func(s *Stmt) (err error) {
if ok, err := s.Next(); err != nil { if err = s.Scan(nil, &name, &file); err != nil {
return nil, err return
} else if !ok {
break
} }
err = s.Scan(nil, &name, &file) databases[name] = file
return
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
databases[name] = file
}
return databases, nil return databases, nil
} }
...@@ -50,19 +48,14 @@ func (c *Conn) Tables() ([]string, error) { ...@@ -50,19 +48,14 @@ func (c *Conn) Tables() ([]string, error) {
} }
defer s.Finalize() defer s.Finalize()
var tables []string = make([]string, 0, 20) var tables []string = make([]string, 0, 20)
var name string err = s.Select(func(s *Stmt) (err error) {
for { name, _ := s.ScanText(0)
if ok, err := s.Next(); err != nil { tables = append(tables, name)
return nil, err return
} else if !ok { })
break
}
err = s.Scan(&name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
tables = append(tables, name)
}
return tables, nil return tables, nil
} }
...@@ -86,18 +79,16 @@ func (c *Conn) Columns(table string) ([]Column, error) { ...@@ -86,18 +79,16 @@ func (c *Conn) Columns(table string) ([]Column, error) {
} }
defer s.Finalize() defer s.Finalize()
var columns []Column = make([]Column, 0, 20) var columns []Column = make([]Column, 0, 20)
for { err = s.Select(func(s *Stmt) (err error) {
if ok, err := s.Next(); err != nil {
return nil, err
} else if !ok {
break
}
c := Column{} c := Column{}
err = s.Scan(&c.Cid, &c.Name, &c.DataType, &c.NotNull, &c.DfltValue, &c.Pk) if err = s.Scan(&c.Cid, &c.Name, &c.DataType, &c.NotNull, &c.DfltValue, &c.Pk); err != nil {
if err != nil { return
return nil, err
} }
columns = append(columns, c) columns = append(columns, c)
return
})
if err != nil {
return nil, err
} }
return columns, nil return columns, nil
} }
...@@ -120,15 +111,9 @@ func (c *Conn) ForeignKeys(table string) (map[int]*ForeignKey, error) { ...@@ -120,15 +111,9 @@ func (c *Conn) ForeignKeys(table string) (map[int]*ForeignKey, error) {
var fks = make(map[int]*ForeignKey) var fks = make(map[int]*ForeignKey)
var id, seq int var id, seq int
var ref, from, to string var ref, from, to string
for { err = s.Select(func(s *Stmt) (err error) {
if ok, err := s.Next(); err != nil { if err = s.NamedScan("id", &id, "seq", &seq, "table", &ref, "from", &from, "to", &to); err != nil {
return nil, err return
} else if !ok {
break
}
err = s.NamedScan("id", &id, "seq", &seq, "table", &ref, "from", &from, "to", &to)
if err != nil {
return nil, err
} }
fk, ex := fks[id] fk, ex := fks[id]
if !ex { if !ex {
...@@ -138,6 +123,10 @@ func (c *Conn) ForeignKeys(table string) (map[int]*ForeignKey, error) { ...@@ -138,6 +123,10 @@ func (c *Conn) ForeignKeys(table string) (map[int]*ForeignKey, error) {
// TODO Ensure columns are appended in the correct order... // TODO Ensure columns are appended in the correct order...
fk.From = append(fk.From, from) fk.From = append(fk.From, from)
fk.To = append(fk.To, to) fk.To = append(fk.To, to)
return
})
if err != nil {
return nil, err
} }
return fks, nil return fks, nil
} }
...@@ -157,18 +146,16 @@ func (c *Conn) Indexes(table string) ([]Index, error) { ...@@ -157,18 +146,16 @@ func (c *Conn) Indexes(table string) ([]Index, error) {
} }
defer s.Finalize() defer s.Finalize()
var indexes []Index = make([]Index, 0, 5) var indexes []Index = make([]Index, 0, 5)
for { err = s.Select(func(s *Stmt) (err error) {
if ok, err := s.Next(); err != nil {
return nil, err
} else if !ok {
break
}
i := Index{} i := Index{}
err = s.Scan(nil, &i.Name, &i.Unique) if err = s.Scan(nil, &i.Name, &i.Unique); err != nil {
if err != nil { return
return nil, err
} }
indexes = append(indexes, i) indexes = append(indexes, i)
return
})
if err != nil {
return nil, err
} }
return indexes, nil return indexes, nil
} }
...@@ -182,18 +169,16 @@ func (c *Conn) IndexColumns(index string) ([]Column, error) { ...@@ -182,18 +169,16 @@ func (c *Conn) IndexColumns(index string) ([]Column, error) {
} }
defer s.Finalize() defer s.Finalize()
var columns []Column = make([]Column, 0, 5) var columns []Column = make([]Column, 0, 5)
for { err = s.Select(func(s *Stmt) (err error) {
if ok, err := s.Next(); err != nil {
return nil, err
} else if !ok {
break
}
c := Column{} c := Column{}
err = s.Scan(nil, &c.Cid, &c.Name) if err = s.Scan(nil, &c.Cid, &c.Name); err != nil {
if err != nil { return
return nil, err
} }
columns = append(columns, c) columns = append(columns, c)
return
})
if err != nil {
return nil, err
} }
return columns, nil return columns, nil
} }
......
...@@ -532,7 +532,7 @@ func (s *Stmt) Exec(args ...interface{}) error { ...@@ -532,7 +532,7 @@ func (s *Stmt) Exec(args ...interface{}) error {
// Like Exec but returns the number of rows that were changed or inserted or deleted. // Like Exec but returns the number of rows that were changed or inserted or deleted.
// Don't use it with SELECT or anything that returns data. // Don't use it with SELECT or anything that returns data.
func (s *Stmt) ExecUpdate(args ...interface{}) (int, error) { func (s *Stmt) ExecDml(args ...interface{}) (int, error) {
err := s.Exec(args...) err := s.Exec(args...)
if err != nil { if err != nil {
return -1, err return -1, err
...@@ -540,10 +540,10 @@ func (s *Stmt) ExecUpdate(args ...interface{}) (int, error) { ...@@ -540,10 +540,10 @@ func (s *Stmt) ExecUpdate(args ...interface{}) (int, error) {
return s.c.Changes(), nil return s.c.Changes(), nil
} }
// Like Exec but returns the autoincremented rowid. // Like ExecDml but returns the autoincremented rowid.
// Don't use it with SELECT or anything that returns data. // Don't use it with SELECT or anything that returns data.
func (s *Stmt) ExecInsert(args ...interface{}) (int64, error) { func (s *Stmt) Insert(args ...interface{}) (int64, error) {
n, err := s.ExecUpdate(args...) n, err := s.ExecDml(args...)
if err != nil { if err != nil {
return -1, err return -1, err
} }
...@@ -553,6 +553,29 @@ func (s *Stmt) ExecInsert(args ...interface{}) (int64, error) { ...@@ -553,6 +553,29 @@ func (s *Stmt) ExecInsert(args ...interface{}) (int64, error) {
return s.c.LastInsertRowid(), nil return s.c.LastInsertRowid(), nil
} }
// The callback function is invoked for each result row coming out of the statement.
//
// s, err := c.Prepare(...)
// // TODO error handling
// defer s.Finalize()
// err = s.Select(func(s *Stmt) error {
// //Scan
// })
// // TODO error handling
func (s *Stmt) Select(rowCallbackHandler func(s *Stmt) error) error {
for {
if ok, err := s.Next(); err != nil {
return err
} else if !ok {
break
}
if err := rowCallbackHandler(s); err != nil {
return err
}
}
return nil
}
// Number of SQL parameters // Number of SQL parameters
// Calls http://sqlite.org/c3ref/bind_parameter_count.html // Calls http://sqlite.org/c3ref/bind_parameter_count.html
func (s *Stmt) BindParameterCount() int { func (s *Stmt) BindParameterCount() int {
...@@ -789,11 +812,14 @@ func (s *Stmt) ColumnType(index int) Type { ...@@ -789,11 +812,14 @@ func (s *Stmt) ColumnType(index int) Type {
// defer stmt.Finalize() // defer stmt.Finalize()
// var id int // var id int
// var name string // var name string
// for sqlite.Must(stmt.Next()) { // err = s.Select(func(s *Stmt) (err error) {
// err = stmt.NamedScan("name", &name, "id", &id) // if err = stmt.NamedScan("name", &name, "id", &id); err != nil {
// // TODO error handling // return
// fmt.Println(id, name)
// } // }
// fmt.Println(id, name)
// return
// })
// // TODO error handling
// //
// NULL value is converted to 0 if arg type is *int,*int64,*float,*float64, to "" for *string, to []byte{} for *[]byte and to false for *bool. // NULL value is converted to 0 if arg type is *int,*int64,*float,*float64, to "" for *string, to []byte{} for *[]byte and to false for *bool.
// Calls sqlite3_column_count, sqlite3_column_name and sqlite3_column_(blob|double|int|int64|text) depending on args type. // Calls sqlite3_column_count, sqlite3_column_name and sqlite3_column_(blob|double|int|int64|text) depending on args type.
...@@ -827,11 +853,14 @@ func (s *Stmt) NamedScan(args ...interface{}) error { ...@@ -827,11 +853,14 @@ func (s *Stmt) NamedScan(args ...interface{}) error {
// defer stmt.Finalize() // defer stmt.Finalize()
// var id int // var id int
// var name string // var name string
// for sqlite.Must(stmt.Next()) { // err = s.Select(func(s *Stmt) error {
// err = stmt.Scan(&id, &name) // if err = stmt.Scan(&id, &name); err != nil {
// // TODO error handling // return
// fmt.Println(id, name)
// } // }
// fmt.Println(id, name)
// return
// })
// // TODO error handling
// //
// NULL value is converted to 0 if arg type is *int,*int64,*float,*float64, to "" for *string, to []byte{} for *[]byte and to false for *bool. // NULL value is converted to 0 if arg type is *int,*int64,*float,*float64, to "" for *string, to []byte{} for *[]byte and to false for *bool.
// TODO How to avoid NULL conversion? // TODO How to avoid NULL conversion?
......
...@@ -167,7 +167,7 @@ func TestInsertWithStatement(t *testing.T) { ...@@ -167,7 +167,7 @@ func TestInsertWithStatement(t *testing.T) {
db.Begin() db.Begin()
for i := 0; i < 1000; i++ { for i := 0; i < 1000; i++ {
c, ierr := s.ExecUpdate(float64(i)*float64(3.14), i, "hello") c, ierr := s.ExecDml(float64(i)*float64(3.14), i, "hello")
checkNoError(t, ierr, "insert error: %s") checkNoError(t, ierr, "insert error: %s")
if c != 1 { if c != 1 {
t.Errorf("insert error: %d but got 1", c) t.Errorf("insert error: %d but got 1", c)
......
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