Commit 91c0ce3d authored by gwenn's avatar gwenn

Null check during scan cannot be disabled anymore.

parent b095b565
...@@ -44,12 +44,12 @@ func (c *connImpl) Exec(query string, args []driver.Value) (driver.Result, error ...@@ -44,12 +44,12 @@ func (c *connImpl) Exec(query string, args []driver.Value) (driver.Result, error
return c, nil // FIXME RowAffected/noRows return c, nil // FIXME RowAffected/noRows
} }
// TODO How to know that the last Stmt did an INSERT? // TODO How to know that the last Stmt has done an INSERT? An authorizer?
func (c *connImpl) LastInsertId() (int64, error) { func (c *connImpl) LastInsertId() (int64, error) {
return c.c.LastInsertRowid(), nil return c.c.LastInsertRowid(), nil
} }
// TODO How to know that the last Stmt did an DELETE/INSERT/UPDATE? // TODO How to know that the last Stmt has done a DELETE/INSERT/UPDATE? An authorizer?
func (c *connImpl) RowsAffected() (int64, error) { func (c *connImpl) RowsAffected() (int64, error) {
return int64(c.c.Changes()), nil return int64(c.c.Changes()), nil
} }
...@@ -98,12 +98,12 @@ func (s *stmtImpl) Exec(args []driver.Value) (driver.Result, error) { ...@@ -98,12 +98,12 @@ func (s *stmtImpl) Exec(args []driver.Value) (driver.Result, error) {
return s, nil // FIXME RowAffected/noRows return s, nil // FIXME RowAffected/noRows
} }
// TODO How to know that this Stmt did an INSERT? // TODO How to know that this Stmt has done an INSERT? An authorizer?
func (s *stmtImpl) LastInsertId() (int64, error) { func (s *stmtImpl) LastInsertId() (int64, error) {
return s.s.c.LastInsertRowid(), nil return s.s.c.LastInsertRowid(), nil
} }
// TODO How to know that this Stmt did an DELETE/INSERT/UPDATE? // TODO How to know that this Stmt has done a DELETE/INSERT/UPDATE? An authorizer?
func (s *stmtImpl) RowsAffected() (int64, error) { func (s *stmtImpl) RowsAffected() (int64, error) {
return int64(s.s.c.Changes()), nil return int64(s.s.c.Changes()), nil
} }
......
...@@ -395,6 +395,7 @@ func (c *Conn) OneValue(query string, value interface{}, args ...interface{}) er ...@@ -395,6 +395,7 @@ func (c *Conn) OneValue(query string, value interface{}, args ...interface{}) er
} }
// Count the number of rows modified // Count the number of rows modified
// If a separate thread makes changes on the same database connection while Changes() is running then the value returned is unpredictable and not meaningful.
// (See http://sqlite.org/c3ref/changes.html) // (See http://sqlite.org/c3ref/changes.html)
func (c *Conn) Changes() int { func (c *Conn) Changes() int {
return int(C.sqlite3_changes(c.db)) return int(C.sqlite3_changes(c.db))
...@@ -407,6 +408,7 @@ func (c *Conn) TotalChanges() int { ...@@ -407,6 +408,7 @@ func (c *Conn) TotalChanges() int {
} }
// Return the rowid of the most recent successful INSERT into the database. // Return the rowid of the most recent successful INSERT into the database.
// If a separate thread performs a new INSERT on the same database connection while the LastInsertRowid() function is running and thus changes the last insert rowid, then the value returned by LastInsertRowid() is unpredictable and might not equal either the old or the new last insert rowid.
// (See http://sqlite.org/c3ref/last_insert_rowid.html) // (See http://sqlite.org/c3ref/last_insert_rowid.html)
func (c *Conn) LastInsertRowid() int64 { func (c *Conn) LastInsertRowid() int64 {
return int64(C.sqlite3_last_insert_rowid(c.db)) return int64(C.sqlite3_last_insert_rowid(c.db))
...@@ -472,11 +474,12 @@ func (c *Conn) exec(cmd string) error { ...@@ -472,11 +474,12 @@ func (c *Conn) exec(cmd string) error {
type Stmt struct { type Stmt struct {
c *Conn c *Conn
stmt *C.sqlite3_stmt stmt *C.sqlite3_stmt
sql string
tail string tail string
columnCount int
cols map[string]int // cached columns index by name cols map[string]int // cached columns index by name
bindParameterCount int
params map[string]int // cached parameter index by name params map[string]int // cached parameter index by name
// Enable NULL value check in Scan methods
CheckNull bool
// Enable type check in Scan methods // Enable type check in Scan methods
CheckTypeMismatch bool CheckTypeMismatch bool
} }
...@@ -506,7 +509,7 @@ func (c *Conn) Prepare(cmd string, args ...interface{}) (*Stmt, error) { ...@@ -506,7 +509,7 @@ func (c *Conn) Prepare(cmd string, args ...interface{}) (*Stmt, error) {
if tail != nil && C.strlen(tail) > 0 { if tail != nil && C.strlen(tail) > 0 {
t = C.GoString(tail) t = C.GoString(tail)
} }
s := &Stmt{c: c, stmt: stmt, tail: t, CheckNull: true, CheckTypeMismatch: true} s := &Stmt{c: c, stmt: stmt, tail: t, columnCount: -1, bindParameterCount: -1, CheckTypeMismatch: true}
if len(args) > 0 { if len(args) > 0 {
err := s.Bind(args...) err := s.Bind(args...)
if err != nil { if err != nil {
...@@ -584,7 +587,10 @@ func (s *Stmt) Select(rowCallbackHandler func(s *Stmt) error) error { ...@@ -584,7 +587,10 @@ func (s *Stmt) Select(rowCallbackHandler func(s *Stmt) error) error {
// Number of SQL parameters // Number of SQL parameters
// (See http://sqlite.org/c3ref/bind_parameter_count.html) // (See http://sqlite.org/c3ref/bind_parameter_count.html)
func (s *Stmt) BindParameterCount() int { func (s *Stmt) BindParameterCount() int {
return int(C.sqlite3_bind_parameter_count(s.stmt)) if s.bindParameterCount == -1 {
s.bindParameterCount = int(C.sqlite3_bind_parameter_count(s.stmt))
}
return s.bindParameterCount
} }
// Index of a parameter with a given name (cached) // Index of a parameter with a given name (cached)
...@@ -609,7 +615,7 @@ func (s *Stmt) BindParameterIndex(name string) (int, error) { ...@@ -609,7 +615,7 @@ func (s *Stmt) BindParameterIndex(name string) (int, error) {
return index, nil return index, nil
} }
// Name of a host parameter // Name of a host parameter (not cached)
// The first host parameter has an index of 1, not 0. // The first host parameter has an index of 1, not 0.
// (See http://sqlite.org/c3ref/bind_parameter_name.html) // (See http://sqlite.org/c3ref/bind_parameter_name.html)
func (s *Stmt) BindParameterName(i int) (string, error) { func (s *Stmt) BindParameterName(i int) (string, error) {
...@@ -745,19 +751,23 @@ func (s *Stmt) ClearBindings() error { ...@@ -745,19 +751,23 @@ func (s *Stmt) ClearBindings() error {
return s.error(C.sqlite3_clear_bindings(s.stmt)) return s.error(C.sqlite3_clear_bindings(s.stmt))
} }
// Number of columns in a result set // Number of columns in a result set (with or without row)
// (See http://sqlite.org/c3ref/column_count.html) // (See http://sqlite.org/c3ref/column_count.html)
func (s *Stmt) ColumnCount() int { func (s *Stmt) ColumnCount() int {
return int(C.sqlite3_column_count(s.stmt)) if s.columnCount == -1 {
s.columnCount = int(C.sqlite3_column_count(s.stmt))
}
return s.columnCount
} }
// Number of columns in a result set // Number of columns in a result set
// Same as ColumnCount() except when there is no (more) row, it returns 0
// (See http://sqlite.org/c3ref/data_count.html) // (See http://sqlite.org/c3ref/data_count.html)
func (s *Stmt) DataCount() int { func (s *Stmt) DataCount() int {
return int(C.sqlite3_data_count(s.stmt)) return int(C.sqlite3_data_count(s.stmt))
} }
// Column name in a result set // Column name in a result set (not cached)
// The leftmost column is number 0. // The leftmost column is number 0.
// (See http://sqlite.org/c3ref/column_name.html) // (See http://sqlite.org/c3ref/column_name.html)
func (s *Stmt) ColumnName(index int) string { func (s *Stmt) ColumnName(index int) string {
...@@ -765,7 +775,7 @@ func (s *Stmt) ColumnName(index int) string { ...@@ -765,7 +775,7 @@ func (s *Stmt) ColumnName(index int) string {
return C.GoString(C.sqlite3_column_name(s.stmt, C.int(index))) return C.GoString(C.sqlite3_column_name(s.stmt, C.int(index)))
} }
// Column names in a result set // Column names in a result set (not cached)
func (s *Stmt) ColumnNames() []string { func (s *Stmt) ColumnNames() []string {
count := s.ColumnCount() count := s.ColumnCount()
names := make([]string, count) names := make([]string, count)
...@@ -800,6 +810,8 @@ var typeText = map[Type]string{ ...@@ -800,6 +810,8 @@ var typeText = map[Type]string{
// Return the datatype code for the initial data type of the result column. // Return the datatype code for the initial data type of the result column.
// The leftmost column is number 0. // The leftmost column is number 0.
// Should not be cached (valid only for one row) (see dynamic type http://www.sqlite.org/datatype3.html)
//
// After a type conversion, the value returned by sqlite3_column_type() is undefined. // After a type conversion, the value returned by sqlite3_column_type() is undefined.
// (See sqlite3_column_type: http://sqlite.org/c3ref/column_blob.html) // (See sqlite3_column_type: http://sqlite.org/c3ref/column_blob.html)
func (s *Stmt) ColumnType(index int) Type { func (s *Stmt) ColumnType(index int) Type {
...@@ -885,7 +897,10 @@ func (s *Stmt) Scan(args ...interface{}) error { ...@@ -885,7 +897,10 @@ func (s *Stmt) Scan(args ...interface{}) error {
// Retrieve statement SQL // Retrieve statement SQL
// (See http://sqlite.org/c3ref/sql.html) // (See http://sqlite.org/c3ref/sql.html)
func (s *Stmt) SQL() string { func (s *Stmt) SQL() string {
return C.GoString(C.sqlite3_sql(s.stmt)) if s.sql == "" {
s.sql = C.GoString(C.sqlite3_sql(s.stmt))
}
return s.sql
} }
// Column index in a result set for a given column name // Column index in a result set for a given column name
...@@ -907,7 +922,7 @@ func (s *Stmt) ColumnIndex(name string) (int, error) { ...@@ -907,7 +922,7 @@ func (s *Stmt) ColumnIndex(name string) (int, error) {
return -1, s.specificError("invalid column name: %s", name) return -1, s.specificError("invalid column name: %s", name)
} }
// Returns true when column is null and Stmt.CheckNull is activated. // Returns true when column is null.
// Calls sqlite3_column_(blob|double|int|int64|text) depending on arg type. // Calls sqlite3_column_(blob|double|int|int64|text) depending on arg type.
// (See http://sqlite.org/c3ref/column_blob.html) // (See http://sqlite.org/c3ref/column_blob.html)
func (s *Stmt) ScanByName(name string, value interface{}) (bool, error) { func (s *Stmt) ScanByName(name string, value interface{}) (bool, error) {
...@@ -929,7 +944,7 @@ func (s *Stmt) ScanByName(name string, value interface{}) (bool, error) { ...@@ -929,7 +944,7 @@ func (s *Stmt) ScanByName(name string, value interface{}) (bool, error) {
// (*)*[]byte // (*)*[]byte
// *interface{} // *interface{}
// //
// Returns true when column is null and Stmt.CheckNull is activated. // Returns true when column is null.
// Calls sqlite3_column_(blob|double|int|int64|text) depending on arg type. // Calls sqlite3_column_(blob|double|int|int64|text) depending on arg type.
// (See http://sqlite.org/c3ref/column_blob.html) // (See http://sqlite.org/c3ref/column_blob.html)
func (s *Stmt) ScanByIndex(index int, value interface{}) (bool, error) { func (s *Stmt) ScanByIndex(index int, value interface{}) (bool, error) {
...@@ -1082,14 +1097,11 @@ func (s *Stmt) ScanText(index int) (value string, isNull bool) { ...@@ -1082,14 +1097,11 @@ func (s *Stmt) ScanText(index int) (value string, isNull bool) {
} }
// The leftmost column/index is number 0. // The leftmost column/index is number 0.
// Returns true when column is null and Stmt.CheckNull is activated. // Returns true when column is null.
// (See sqlite3_column_int: http://sqlite.org/c3ref/column_blob.html) // (See sqlite3_column_int: http://sqlite.org/c3ref/column_blob.html)
func (s *Stmt) ScanInt(index int) (value int, isNull bool, err error) { func (s *Stmt) ScanInt(index int) (value int, isNull bool, err error) {
var ctype Type ctype := s.ColumnType(index)
if s.CheckNull || s.CheckTypeMismatch { if ctype == Null {
ctype = s.ColumnType(index)
}
if s.CheckNull && ctype == Null {
isNull = true isNull = true
} else { } else {
if s.CheckTypeMismatch { if s.CheckTypeMismatch {
...@@ -1101,14 +1113,11 @@ func (s *Stmt) ScanInt(index int) (value int, isNull bool, err error) { ...@@ -1101,14 +1113,11 @@ func (s *Stmt) ScanInt(index int) (value int, isNull bool, err error) {
} }
// The leftmost column/index is number 0. // The leftmost column/index is number 0.
// Returns true when column is null and Stmt.CheckNull is activated. // Returns true when column is null.
// (See sqlite3_column_int64: http://sqlite.org/c3ref/column_blob.html) // (See sqlite3_column_int64: http://sqlite.org/c3ref/column_blob.html)
func (s *Stmt) ScanInt64(index int) (value int64, isNull bool, err error) { func (s *Stmt) ScanInt64(index int) (value int64, isNull bool, err error) {
var ctype Type ctype := s.ColumnType(index)
if s.CheckNull || s.CheckTypeMismatch { if ctype == Null {
ctype = s.ColumnType(index)
}
if s.CheckNull && ctype == Null {
isNull = true isNull = true
} else { } else {
if s.CheckTypeMismatch { if s.CheckTypeMismatch {
...@@ -1120,14 +1129,11 @@ func (s *Stmt) ScanInt64(index int) (value int64, isNull bool, err error) { ...@@ -1120,14 +1129,11 @@ func (s *Stmt) ScanInt64(index int) (value int64, isNull bool, err error) {
} }
// The leftmost column/index is number 0. // The leftmost column/index is number 0.
// Returns true when column is null and Stmt.CheckNull is activated. // Returns true when column is null.
// (See sqlite3_column_int: http://sqlite.org/c3ref/column_blob.html) // (See sqlite3_column_int: http://sqlite.org/c3ref/column_blob.html)
func (s *Stmt) ScanByte(index int) (value byte, isNull bool, err error) { func (s *Stmt) ScanByte(index int) (value byte, isNull bool, err error) {
var ctype Type ctype := s.ColumnType(index)
if s.CheckNull || s.CheckTypeMismatch { if ctype == Null {
ctype = s.ColumnType(index)
}
if s.CheckNull && ctype == Null {
isNull = true isNull = true
} else { } else {
if s.CheckTypeMismatch { if s.CheckTypeMismatch {
...@@ -1139,14 +1145,11 @@ func (s *Stmt) ScanByte(index int) (value byte, isNull bool, err error) { ...@@ -1139,14 +1145,11 @@ func (s *Stmt) ScanByte(index int) (value byte, isNull bool, err error) {
} }
// The leftmost column/index is number 0. // The leftmost column/index is number 0.
// Returns true when column is null and Stmt.CheckNull is activated. // Returns true when column is null.
// (See sqlite3_column_int: http://sqlite.org/c3ref/column_blob.html) // (See sqlite3_column_int: http://sqlite.org/c3ref/column_blob.html)
func (s *Stmt) ScanBool(index int) (value bool, isNull bool, err error) { func (s *Stmt) ScanBool(index int) (value bool, isNull bool, err error) {
var ctype Type ctype := s.ColumnType(index)
if s.CheckNull || s.CheckTypeMismatch { if ctype == Null {
ctype = s.ColumnType(index)
}
if s.CheckNull && ctype == Null {
isNull = true isNull = true
} else { } else {
if s.CheckTypeMismatch { if s.CheckTypeMismatch {
...@@ -1158,14 +1161,11 @@ func (s *Stmt) ScanBool(index int) (value bool, isNull bool, err error) { ...@@ -1158,14 +1161,11 @@ func (s *Stmt) ScanBool(index int) (value bool, isNull bool, err error) {
} }
// The leftmost column/index is number 0. // The leftmost column/index is number 0.
// Returns true when column is null and Stmt.CheckNull is activated. // Returns true when column is null.
// (See sqlite3_column_double: http://sqlite.org/c3ref/column_blob.html) // (See sqlite3_column_double: http://sqlite.org/c3ref/column_blob.html)
func (s *Stmt) ScanDouble(index int) (value float64, isNull bool, err error) { func (s *Stmt) ScanDouble(index int) (value float64, isNull bool, err error) {
var ctype Type ctype := s.ColumnType(index)
if s.CheckNull || s.CheckTypeMismatch { if ctype == Null {
ctype = s.ColumnType(index)
}
if s.CheckNull && ctype == Null {
isNull = true isNull = true
} else { } else {
if s.CheckTypeMismatch { if s.CheckTypeMismatch {
......
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