Commit 4d9000a7 authored by gwenn's avatar gwenn

Ensures the column index is valid.

parent 014b1ec7
...@@ -331,8 +331,9 @@ func (s *Stmt) ExportToCSV(nullvalue string, headers bool, w *yacr.Writer) error ...@@ -331,8 +331,9 @@ func (s *Stmt) ExportToCSV(nullvalue string, headers bool, w *yacr.Writer) error
} }
s.Select(func(s *Stmt) error { s.Select(func(s *Stmt) error {
for i := 0; i < s.ColumnCount(); i++ { for i := 0; i < s.ColumnCount(); i++ {
rb, null := s.ScanRawBytes(i) if rb, null, err := s.ScanRawBytes(i); err != nil {
if null { return err
} else if null {
w.Write([]byte(nullvalue)) w.Write([]byte(nullvalue))
} else { } else {
w.Write(rb) w.Write(rb)
......
...@@ -206,17 +206,22 @@ func TestImportAffinity(t *testing.T) { ...@@ -206,17 +206,22 @@ func TestImportAffinity(t *testing.T) {
err := db.ImportCSV(r, ic, "", "test") err := db.ImportCSV(r, ic, "", "test")
checkNoError(t, err, "error while importing CSV file: %s") checkNoError(t, err, "error while importing CSV file: %s")
err = db.Select("SELECT typeof(t), typeof(i), typeof(r), typeof(b), typeof(n) from test", func(s *Stmt) error { err = db.Select("SELECT typeof(t), typeof(i), typeof(r), typeof(b), typeof(n) from test", func(s *Stmt) error {
tot, _ := s.ScanText(0) tot, _, err := s.ScanText(0)
checkNoError(t, err, "error while scanning: %s")
assert.Equal(t, "text", tot) assert.Equal(t, "text", tot)
toi, _ := s.ScanText(1) toi, _, err := s.ScanText(1)
checkNoError(t, err, "error while scanning: %s")
assert.Equal(t, "integer", toi) assert.Equal(t, "integer", toi)
tor, _ := s.ScanText(2) tor, _, err := s.ScanText(2)
checkNoError(t, err, "error while scanning: %s")
assert.Equal(t, "real", tor) assert.Equal(t, "real", tor)
tob, _ := s.ScanText(3) tob, _, err := s.ScanText(3)
checkNoError(t, err, "error while scanning: %s")
assert.Equal(t, "text", tob) assert.Equal(t, "text", tob)
ton, _ := s.ScanText(4) ton, _, err := s.ScanText(4)
checkNoError(t, err, "error while scanning: %s")
assert.Equal(t, "integer", ton) assert.Equal(t, "integer", ton)
return nil return err
}) })
checkNoError(t, err, "error while selecting: %s") checkNoError(t, err, "error while selecting: %s")
} }
......
...@@ -229,7 +229,9 @@ func (r *rowsImpl) Next(dest []driver.Value) error { ...@@ -229,7 +229,9 @@ func (r *rowsImpl) Next(dest []driver.Value) error {
return io.EOF return io.EOF
} }
for i := range dest { for i := range dest {
dest[i], _ = r.s.s.ScanValue(i, true) if dest[i], _, err = r.s.s.ScanValue(i, true); err != nil {
return err
}
/*if !driver.IsScanValue(dest[i]) { /*if !driver.IsScanValue(dest[i]) {
panic("Invalid type returned by ScanValue") panic("Invalid type returned by ScanValue")
}*/ }*/
......
...@@ -56,8 +56,11 @@ func (c *Conn) Tables(dbName string) ([]string, error) { ...@@ -56,8 +56,11 @@ func (c *Conn) Tables(dbName string) ([]string, error) {
defer s.finalize() defer s.finalize()
var tables = make([]string, 0, 20) var tables = make([]string, 0, 20)
err = s.Select(func(s *Stmt) (err error) { err = s.Select(func(s *Stmt) (err error) {
name, _ := s.ScanText(0) if name, _, err := s.ScanText(0); err != nil {
tables = append(tables, name) return err
} else {
tables = append(tables, name)
}
return return
}) })
if err != nil { if err != nil {
...@@ -84,8 +87,11 @@ func (c *Conn) Views(dbName string) ([]string, error) { ...@@ -84,8 +87,11 @@ func (c *Conn) Views(dbName string) ([]string, error) {
defer s.finalize() defer s.finalize()
var views = make([]string, 0, 20) var views = make([]string, 0, 20)
err = s.Select(func(s *Stmt) (err error) { err = s.Select(func(s *Stmt) (err error) {
name, _ := s.ScanText(0) if name, _, err := s.ScanText(0); err != nil {
views = append(views, name) return err
} else {
views = append(views, name)
}
return return
}) })
if err != nil { if err != nil {
...@@ -172,8 +178,11 @@ func (c *Conn) Columns(dbName, table string) ([]Column, error) { ...@@ -172,8 +178,11 @@ func (c *Conn) Columns(dbName, table string) ([]Column, error) {
// If the result column is an expression or subquery, then an empty string is returned. // If the result column is an expression or subquery, then an empty string is returned.
// The left-most column is column 0. // The left-most column is column 0.
// (See http://www.sqlite.org/c3ref/column_decltype.html) // (See http://www.sqlite.org/c3ref/column_decltype.html)
func (s *Stmt) ColumnDeclaredType(index int) string { func (s *Stmt) ColumnDeclaredType(index int) (string, error) {
return C.GoString(C.sqlite3_column_decltype(s.stmt, C.int(index))) if index < 0 || index >= s.ColumnCount() {
return "", s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
return C.GoString(C.sqlite3_column_decltype(s.stmt, C.int(index))), nil
} }
// Affinity enumerates SQLite column type affinity // Affinity enumerates SQLite column type affinity
...@@ -192,7 +201,13 @@ const ( ...@@ -192,7 +201,13 @@ const (
// If the result column is an expression or subquery, then None is returned. // If the result column is an expression or subquery, then None is returned.
// The left-most column is column 0. // The left-most column is column 0.
// (See http://sqlite.org/datatype3.html) // (See http://sqlite.org/datatype3.html)
func (s *Stmt) ColumnTypeAffinity(index int) Affinity { func (s *Stmt) ColumnTypeAffinity(index int) (Affinity, error) {
if index < 0 || index >= s.ColumnCount() {
return None, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
return s.columnTypeAffinity(index), nil
}
func (s *Stmt) columnTypeAffinity(index int) Affinity {
if s.affinities == nil { if s.affinities == nil {
count := s.ColumnCount() count := s.ColumnCount()
s.affinities = make([]Affinity, count) s.affinities = make([]Affinity, count)
...@@ -201,7 +216,7 @@ func (s *Stmt) ColumnTypeAffinity(index int) Affinity { ...@@ -201,7 +216,7 @@ func (s *Stmt) ColumnTypeAffinity(index int) Affinity {
return affinity return affinity
} }
} }
declType := s.ColumnDeclaredType(index) declType, _ := s.ColumnDeclaredType(index)
affinity := typeAffinity(declType) affinity := typeAffinity(declType)
s.affinities[index] = affinity s.affinities[index] = affinity
return affinity return affinity
......
...@@ -46,22 +46,31 @@ func (c *Conn) Column(dbName, tableName, columnName string) (*Column, error) { ...@@ -46,22 +46,31 @@ func (c *Conn) Column(dbName, tableName, columnName string) (*Column, error) {
// that is the origin of a particular result column in SELECT statement. // that is the origin of a particular result column in SELECT statement.
// The left-most column is column 0. // The left-most column is column 0.
// (See http://www.sqlite.org/c3ref/column_database_name.html) // (See http://www.sqlite.org/c3ref/column_database_name.html)
func (s *Stmt) ColumnDatabaseName(index int) string { func (s *Stmt) ColumnDatabaseName(index int) (string, error) {
return C.GoString(C.sqlite3_column_database_name(s.stmt, C.int(index))) if index < 0 || index >= s.ColumnCount() {
return "", s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
return C.GoString(C.sqlite3_column_database_name(s.stmt, C.int(index))), nil
} }
// ColumnTableName returns the original un-aliased table name // ColumnTableName returns the original un-aliased table name
// that is the origin of a particular result column in SELECT statement. // that is the origin of a particular result column in SELECT statement.
// The left-most column is column 0. // The left-most column is column 0.
// (See http://www.sqlite.org/c3ref/column_database_name.html) // (See http://www.sqlite.org/c3ref/column_database_name.html)
func (s *Stmt) ColumnTableName(index int) string { func (s *Stmt) ColumnTableName(index int) (string, error) {
return C.GoString(C.sqlite3_column_table_name(s.stmt, C.int(index))) if index < 0 || index >= s.ColumnCount() {
return "", s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
return C.GoString(C.sqlite3_column_table_name(s.stmt, C.int(index))), nil
} }
// ColumnOriginName returns the original un-aliased table column name // ColumnOriginName returns the original un-aliased table column name
// that is the origin of a particular result column in SELECT statement. // that is the origin of a particular result column in SELECT statement.
// The left-most column is column 0. // The left-most column is column 0.
// (See http://www.sqlite.org/c3ref/column_database_name.html) // (See http://www.sqlite.org/c3ref/column_database_name.html)
func (s *Stmt) ColumnOriginName(index int) string { func (s *Stmt) ColumnOriginName(index int) (string, error) {
return C.GoString(C.sqlite3_column_origin_name(s.stmt, C.int(index))) if index < 0 || index >= s.ColumnCount() {
return "", s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
return C.GoString(C.sqlite3_column_origin_name(s.stmt, C.int(index))), nil
} }
...@@ -40,15 +40,20 @@ func TestColumnMetadata(t *testing.T) { ...@@ -40,15 +40,20 @@ func TestColumnMetadata(t *testing.T) {
check(err) check(err)
defer checkFinalize(s, t) defer checkFinalize(s, t)
databaseName := s.ColumnDatabaseName(0) databaseName, err := s.ColumnDatabaseName(0)
check(err)
assert.Equal(t, "main", databaseName, "database name") assert.Equal(t, "main", databaseName, "database name")
tableName := s.ColumnTableName(0) tableName, err := s.ColumnTableName(0)
check(err)
assert.Equal(t, "sqlite_master", tableName, "table name") assert.Equal(t, "sqlite_master", tableName, "table name")
originName := s.ColumnOriginName(0) originName, err := s.ColumnOriginName(0)
check(err)
assert.Equal(t, "name", originName, "origin name") assert.Equal(t, "name", originName, "origin name")
declType := s.ColumnDeclaredType(0) declType, err := s.ColumnDeclaredType(0)
check(err)
assert.Equal(t, "text", declType, "declared type") assert.Equal(t, "text", declType, "declared type")
affinity := s.ColumnTypeAffinity(0) affinity, err := s.ColumnTypeAffinity(0)
check(err)
assert.Equal(t, Textual, affinity, "affinity") assert.Equal(t, Textual, affinity, "affinity")
} }
...@@ -63,15 +68,20 @@ func TestColumnMetadataOnView(t *testing.T) { ...@@ -63,15 +68,20 @@ func TestColumnMetadataOnView(t *testing.T) {
check(err) check(err)
defer checkFinalize(s, t) defer checkFinalize(s, t)
databaseName := s.ColumnDatabaseName(0) databaseName, err := s.ColumnDatabaseName(0)
check(err)
assert.Equal(t, "main", databaseName, "database name") assert.Equal(t, "main", databaseName, "database name")
tableName := s.ColumnTableName(0) tableName, err := s.ColumnTableName(0)
check(err)
assert.Equal(t, "test", tableName, "table name") assert.Equal(t, "test", tableName, "table name")
originName := s.ColumnOriginName(0) originName, err := s.ColumnOriginName(0)
check(err)
assert.Equal(t, "a_string", originName, "origin name") assert.Equal(t, "a_string", originName, "origin name")
declType := s.ColumnDeclaredType(0) declType, err := s.ColumnDeclaredType(0)
check(err)
assert.Equal(t, "TEXT", declType, "declared type") assert.Equal(t, "TEXT", declType, "declared type")
affinity := s.ColumnTypeAffinity(0) affinity, err := s.ColumnTypeAffinity(0)
check(err)
assert.Equal(t, Textual, affinity, "affinity") assert.Equal(t, Textual, affinity, "affinity")
} }
...@@ -85,14 +95,19 @@ func TestColumnMetadataOnExpr(t *testing.T) { ...@@ -85,14 +95,19 @@ func TestColumnMetadataOnExpr(t *testing.T) {
check(err) check(err)
defer checkFinalize(s, t) defer checkFinalize(s, t)
databaseName := s.ColumnDatabaseName(0) databaseName, err := s.ColumnDatabaseName(0)
check(err)
assert.Equal(t, "", databaseName, "database name") assert.Equal(t, "", databaseName, "database name")
tableName := s.ColumnTableName(0) tableName, err := s.ColumnTableName(0)
check(err)
assert.Equal(t, "", tableName, "table name") assert.Equal(t, "", tableName, "table name")
originName := s.ColumnOriginName(0) originName, err := s.ColumnOriginName(0)
check(err)
assert.Equal(t, "", originName, "origin name") assert.Equal(t, "", originName, "origin name")
declType := s.ColumnDeclaredType(0) declType, err := s.ColumnDeclaredType(0)
check(err)
assert.Equal(t, "", declType, "declared type") assert.Equal(t, "", declType, "declared type")
affinity := s.ColumnTypeAffinity(0) affinity, err := s.ColumnTypeAffinity(0)
check(err)
assert.Equal(t, None, affinity, "affinity") assert.Equal(t, None, affinity, "affinity")
} }
...@@ -198,12 +198,24 @@ func TestColumnTypeAffinity(t *testing.T) { ...@@ -198,12 +198,24 @@ func TestColumnTypeAffinity(t *testing.T) {
checkNoError(t, err, "%s") checkNoError(t, err, "%s")
defer checkFinalize(s, t) defer checkFinalize(s, t)
assert.Equal(t, Integral, s.ColumnTypeAffinity(0), "affinity") aff, err := s.ColumnTypeAffinity(0)
assert.Equal(t, Real, s.ColumnTypeAffinity(1), "affinity") checkNoError(t, err, "%s")
assert.Equal(t, Numerical, s.ColumnTypeAffinity(2), "affinity") assert.Equal(t, Integral, aff, "affinity")
assert.Equal(t, None, s.ColumnTypeAffinity(3), "affinity") aff, err = s.ColumnTypeAffinity(1)
assert.Equal(t, Textual, s.ColumnTypeAffinity(4), "affinity") checkNoError(t, err, "%s")
assert.Equal(t, None, s.ColumnTypeAffinity(5), "affinity") assert.Equal(t, Real, aff, "affinity")
aff, err = s.ColumnTypeAffinity(2)
checkNoError(t, err, "%s")
assert.Equal(t, Numerical, aff, "affinity")
aff, err = s.ColumnTypeAffinity(3)
checkNoError(t, err, "%s")
assert.Equal(t, None, aff, "affinity")
aff, err = s.ColumnTypeAffinity(4)
checkNoError(t, err, "%s")
assert.Equal(t, Textual, aff, "affinity")
aff, err = s.ColumnTypeAffinity(5)
checkNoError(t, err, "%s")
assert.Equal(t, None, aff, "affinity")
} }
func TestExpressionTypeAffinity(t *testing.T) { func TestExpressionTypeAffinity(t *testing.T) {
...@@ -214,8 +226,16 @@ func TestExpressionTypeAffinity(t *testing.T) { ...@@ -214,8 +226,16 @@ func TestExpressionTypeAffinity(t *testing.T) {
checkNoError(t, err, "%s") checkNoError(t, err, "%s")
defer checkFinalize(s, t) defer checkFinalize(s, t)
assert.Equal(t, None, s.ColumnTypeAffinity(0), "affinity") aff, err := s.ColumnTypeAffinity(0)
assert.Equal(t, None, s.ColumnTypeAffinity(1), "affinity") checkNoError(t, err, "%s")
assert.Equal(t, None, s.ColumnTypeAffinity(2), "affinity") assert.Equal(t, None, aff, "affinity")
assert.Equal(t, None, s.ColumnTypeAffinity(3), "affinity") aff, err = s.ColumnTypeAffinity(1)
checkNoError(t, err, "%s")
assert.Equal(t, None, aff, "affinity")
aff, err = s.ColumnTypeAffinity(2)
checkNoError(t, err, "%s")
assert.Equal(t, None, aff, "affinity")
aff, err = s.ColumnTypeAffinity(3)
checkNoError(t, err, "%s")
assert.Equal(t, None, aff, "affinity")
} }
...@@ -107,7 +107,7 @@ func (c *Conn) prepare(sql string, args ...interface{}) (*Stmt, error) { ...@@ -107,7 +107,7 @@ func (c *Conn) prepare(sql string, args ...interface{}) (*Stmt, error) {
return nil, c.error(rv, sql) return nil, c.error(rv, sql)
} }
var t string var t string
if tail != nil && C.strlen(tail) > 0 { if tail != nil && *tail != '\000' {
t = C.GoString(tail) t = C.GoString(tail)
} }
s := &Stmt{c: c, stmt: stmt, tail: t, columnCount: -1, bindParameterCount: -1} s := &Stmt{c: c, stmt: stmt, tail: t, columnCount: -1, bindParameterCount: -1}
...@@ -499,9 +499,12 @@ func (s *Stmt) DataCount() int { ...@@ -499,9 +499,12 @@ func (s *Stmt) DataCount() int {
// ColumnName returns the name of the Nth column of the result set returned by the SQL statement. (not cached) // ColumnName returns the name of the Nth column of the result set returned by the SQL statement. (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, error) {
if index < 0 || index >= s.ColumnCount() {
return "", s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
// If there is no AS clause then the name of the column is unspecified and may change from one release of SQLite to the next. // If there is no AS clause then the name of the column is unspecified and may change from one release of SQLite to the next.
return C.GoString(C.sqlite3_column_name(s.stmt, C.int(index))) return C.GoString(C.sqlite3_column_name(s.stmt, C.int(index))), nil
} }
// ColumnNames returns the name of the columns of the result set returned by the SQL statement. (not cached) // ColumnNames returns the name of the columns of the result set returned by the SQL statement. (not cached)
...@@ -509,7 +512,7 @@ func (s *Stmt) ColumnNames() []string { ...@@ -509,7 +512,7 @@ func (s *Stmt) ColumnNames() []string {
count := s.ColumnCount() count := s.ColumnCount()
names := make([]string, count) names := make([]string, count)
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
names[i] = s.ColumnName(i) names[i], _ = s.ColumnName(i)
} }
return names return names
} }
...@@ -544,8 +547,14 @@ var typeText = map[Type]string{ ...@@ -544,8 +547,14 @@ var typeText = map[Type]string{
// //
// 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, error) {
return Type(C.sqlite3_column_type(s.stmt, C.int(index))) // TODO request all columns type at once if index < 0 || index >= s.ColumnCount() {
return Null, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
return s.columnType(index), nil // TODO request all columns type at once
}
func (s *Stmt) columnType(index int) Type {
return Type(C.sqlite3_column_type(s.stmt, C.int(index)))
} }
// NamedScan scans result values from a query by name (name1, value1, ...). // NamedScan scans result values from a query by name (name1, value1, ...).
...@@ -625,7 +634,8 @@ func (s *Stmt) ColumnIndex(name string) (int, error) { ...@@ -625,7 +634,8 @@ func (s *Stmt) ColumnIndex(name string) (int, error) {
count := s.ColumnCount() count := s.ColumnCount()
s.cols = make(map[string]int, count) s.cols = make(map[string]int, count)
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
s.cols[s.ColumnName(i)] = i n, _ := s.ColumnName(i)
s.cols[n] = i
} }
} }
index, ok := s.cols[name] index, ok := s.cols[name]
...@@ -666,24 +676,27 @@ func (s *Stmt) ScanByName(name string, value interface{}) (isNull bool, err erro ...@@ -666,24 +676,27 @@ func (s *Stmt) ScanByName(name string, value interface{}) (isNull bool, err erro
// Calls sqlite3_column_(blob|double|int|int64|text) depending on arg type/kind. // Calls sqlite3_column_(blob|double|int|int64|text) depending on arg type/kind.
// (See http://sqlite.org/c3ref/column_blob.html) // (See http://sqlite.org/c3ref/column_blob.html)
func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error) { func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error) {
if index < 0 || index >= s.ColumnCount() {
return false, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
switch value := value.(type) { switch value := value.(type) {
case nil: case nil:
case *string: case *string:
*value, isNull = s.ScanText(index) *value, isNull, err = s.ScanText(index)
case **string: case **string:
var st string var st string
st, isNull = s.ScanText(index) if st, isNull, err = s.ScanText(index); err == nil {
if isNull { if isNull {
*value = nil *value = nil
} else { } else {
**value = st **value = st
}
} }
case *int: case *int:
*value, isNull, err = s.ScanInt(index) *value, isNull, err = s.ScanInt(index)
case **int: case **int:
var i int var i int
i, isNull, err = s.ScanInt(index) if i, isNull, err = s.ScanInt(index); err == nil {
if err == nil {
if isNull { if isNull {
*value = nil *value = nil
} else { } else {
...@@ -694,8 +707,7 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error ...@@ -694,8 +707,7 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error
*value, isNull, err = s.ScanInt32(index) *value, isNull, err = s.ScanInt32(index)
case **int32: case **int32:
var i int32 var i int32
i, isNull, err = s.ScanInt32(index) if i, isNull, err = s.ScanInt32(index); err == nil {
if err == nil {
if isNull { if isNull {
*value = nil *value = nil
} else { } else {
...@@ -706,8 +718,7 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error ...@@ -706,8 +718,7 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error
*value, isNull, err = s.ScanInt64(index) *value, isNull, err = s.ScanInt64(index)
case **int64: case **int64:
var i int64 var i int64
i, isNull, err = s.ScanInt64(index) if i, isNull, err = s.ScanInt64(index); err == nil {
if err == nil {
if isNull { if isNull {
*value = nil *value = nil
} else { } else {
...@@ -718,8 +729,7 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error ...@@ -718,8 +729,7 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error
*value, isNull, err = s.ScanByte(index) *value, isNull, err = s.ScanByte(index)
case **byte: case **byte:
var b byte var b byte
b, isNull, err = s.ScanByte(index) if b, isNull, err = s.ScanByte(index); err == nil {
if err == nil {
if isNull { if isNull {
*value = nil *value = nil
} else { } else {
...@@ -730,8 +740,7 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error ...@@ -730,8 +740,7 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error
*value, isNull, err = s.ScanBool(index) *value, isNull, err = s.ScanBool(index)
case **bool: case **bool:
var b bool var b bool
b, isNull, err = s.ScanBool(index) if b, isNull, err = s.ScanBool(index); err == nil {
if err == nil {
if isNull { if isNull {
*value = nil *value = nil
} else { } else {
...@@ -742,8 +751,7 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error ...@@ -742,8 +751,7 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error
*value, isNull, err = s.ScanDouble(index) *value, isNull, err = s.ScanDouble(index)
case **float64: case **float64:
var f float64 var f float64
f, isNull, err = s.ScanDouble(index) if f, isNull, err = s.ScanDouble(index); err == nil {
if err == nil {
if isNull { if isNull {
*value = nil *value = nil
} else { } else {
...@@ -751,23 +759,25 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error ...@@ -751,23 +759,25 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error
} }
} }
case *[]byte: case *[]byte:
*value, isNull = s.ScanBlob(index) *value, isNull, err = s.ScanBlob(index)
case **[]byte: case **[]byte:
var bs []byte var bs []byte
bs, isNull = s.ScanBlob(index) if bs, isNull, err = s.ScanBlob(index); err == nil {
if isNull { if isNull {
*value = nil *value = nil
} else { } else {
**value = bs **value = bs
}
} }
case *time.Time: // go fix doesn't like this type! case *time.Time: // go fix doesn't like this type!
*value, isNull, err = s.ScanTime(index) *value, isNull, err = s.ScanTime(index)
case sql.Scanner: case sql.Scanner:
var v interface{} var v interface{}
v, isNull = s.ScanValue(index, false) if v, isNull, err = s.ScanValue(index, false); err == nil {
err = value.Scan(v) err = value.Scan(v)
}
case *interface{}: case *interface{}:
*value, isNull = s.ScanValue(index, false) *value, isNull, err = s.ScanValue(index, false)
default: default:
return s.ScanReflect(index, value) return s.ScanReflect(index, value)
} }
...@@ -787,6 +797,9 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error ...@@ -787,6 +797,9 @@ func (s *Stmt) ScanByIndex(index int, value interface{}) (isNull bool, err error
// //
// Returns true when column is null. // Returns true when column is null.
func (s *Stmt) ScanReflect(index int, v interface{}) (isNull bool, err error) { func (s *Stmt) ScanReflect(index int, v interface{}) (isNull bool, err error) {
if index < 0 || index >= s.ColumnCount() {
return false, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
rv := reflect.ValueOf(v) rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr || rv.IsNil() { if rv.Kind() != reflect.Ptr || rv.IsNil() {
return false, s.specificError("ScanReflect unsupported type %T", v) return false, s.specificError("ScanReflect unsupported type %T", v)
...@@ -795,18 +808,17 @@ func (s *Stmt) ScanReflect(index int, v interface{}) (isNull bool, err error) { ...@@ -795,18 +808,17 @@ func (s *Stmt) ScanReflect(index int, v interface{}) (isNull bool, err error) {
switch dv.Kind() { switch dv.Kind() {
case reflect.String: case reflect.String:
var t string var t string
t, isNull = s.ScanText(index) if t, isNull, err = s.ScanText(index); err == nil {
dv.SetString(t) dv.SetString(t)
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
var i int64 var i int64
i, isNull, err = s.ScanInt64(index) if i, isNull, err = s.ScanInt64(index); err == nil {
if err == nil {
dv.SetInt(i) dv.SetInt(i)
} }
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
var i int64 var i int64
i, isNull, err = s.ScanInt64(index) if i, isNull, err = s.ScanInt64(index); err == nil {
if err == nil {
if i < 0 { if i < 0 {
err = s.specificError("negative value: %d", i) err = s.specificError("negative value: %d", i)
} else { } else {
...@@ -815,14 +827,12 @@ func (s *Stmt) ScanReflect(index int, v interface{}) (isNull bool, err error) { ...@@ -815,14 +827,12 @@ func (s *Stmt) ScanReflect(index int, v interface{}) (isNull bool, err error) {
} }
case reflect.Bool: case reflect.Bool:
var b bool var b bool
b, isNull, err = s.ScanBool(index) if b, isNull, err = s.ScanBool(index); err == nil {
if err == nil {
dv.SetBool(b) dv.SetBool(b)
} }
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
var f float64 var f float64
f, isNull, err = s.ScanDouble(index) if f, isNull, err = s.ScanDouble(index); err == nil {
if err == nil {
dv.SetFloat(f) dv.SetFloat(f)
} }
default: default:
...@@ -844,56 +854,65 @@ func (s *Stmt) ScanReflect(index int, v interface{}) (isNull bool, err error) { ...@@ -844,56 +854,65 @@ func (s *Stmt) ScanReflect(index int, v interface{}) (isNull bool, err error) {
// //
// Calls sqlite3_column_(blob|double|int|int64|text) depending on columns type. // Calls sqlite3_column_(blob|double|int|int64|text) depending on columns type.
// (See http://sqlite.org/c3ref/column_blob.html) // (See http://sqlite.org/c3ref/column_blob.html)
func (s *Stmt) ScanValue(index int, blob bool) (value interface{}, isNull bool) { func (s *Stmt) ScanValue(index int, blob bool) (value interface{}, isNull bool, err error) {
switch s.ColumnType(index) { if index < 0 || index >= s.ColumnCount() {
return nil, false, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
switch s.columnType(index) {
case Null: case Null:
return nil, true return nil, true, nil
case Text: // does not work as expected if column type affinity is TEXT but inserted value was a numeric case Text: // does not work as expected if column type affinity is TEXT but inserted value was a numeric
if s.c.ScanNumericalAsTime && s.c.DefaultTimeLayout != "" && s.ColumnTypeAffinity(index) == Numerical { if s.c.ScanNumericalAsTime && s.c.DefaultTimeLayout != "" && s.columnTypeAffinity(index) == Numerical {
p := C.sqlite3_column_text(s.stmt, C.int(index)) p := C.sqlite3_column_text(s.stmt, C.int(index))
txt := C.GoString((*C.char)(unsafe.Pointer(p))) txt := C.GoString((*C.char)(unsafe.Pointer(p)))
value, err := time.Parse(s.c.DefaultTimeLayout, txt) value, err := time.Parse(s.c.DefaultTimeLayout, txt)
if err == nil { if err == nil {
return value, false return value, false, nil
} }
Log(-1, err.Error()) Log(-1, err.Error())
} }
if blob { if blob {
p := C.sqlite3_column_blob(s.stmt, C.int(index)) p := C.sqlite3_column_blob(s.stmt, C.int(index))
n := C.sqlite3_column_bytes(s.stmt, C.int(index)) n := C.sqlite3_column_bytes(s.stmt, C.int(index))
return C.GoBytes(p, n), false return C.GoBytes(p, n), false, nil
} }
p := C.sqlite3_column_text(s.stmt, C.int(index)) p := C.sqlite3_column_text(s.stmt, C.int(index))
return C.GoString((*C.char)(unsafe.Pointer(p))), false return C.GoString((*C.char)(unsafe.Pointer(p))), false, nil
case Integer: case Integer:
value := int64(C.sqlite3_column_int64(s.stmt, C.int(index))) value := int64(C.sqlite3_column_int64(s.stmt, C.int(index)))
if s.c.ScanNumericalAsTime && s.c.DefaultTimeLayout == "" && s.ColumnTypeAffinity(index) == Numerical { if s.c.ScanNumericalAsTime && s.c.DefaultTimeLayout == "" && s.columnTypeAffinity(index) == Numerical {
return time.Unix(value, 0), false return time.Unix(value, 0), false, nil
} }
return value, false return value, false, nil
case Float: // does not work as expected if column type affinity is REAL but inserted value was an integer case Float: // does not work as expected if column type affinity is REAL but inserted value was an integer
return float64(C.sqlite3_column_double(s.stmt, C.int(index))), false return float64(C.sqlite3_column_double(s.stmt, C.int(index))), false, nil
case Blob: case Blob:
p := C.sqlite3_column_blob(s.stmt, C.int(index)) p := C.sqlite3_column_blob(s.stmt, C.int(index))
n := C.sqlite3_column_bytes(s.stmt, C.int(index)) n := C.sqlite3_column_bytes(s.stmt, C.int(index))
// value = (*[1 << 30]byte)(unsafe.Pointer(p))[:n] // value = (*[1 << 30]byte)(unsafe.Pointer(p))[:n]
return C.GoBytes(p, n), false // The memory space used to hold strings and BLOBs is freed automatically. return C.GoBytes(p, n), false, nil // The memory space used to hold strings and BLOBs is freed automatically.
} }
panic("The column type is not one of SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB, or SQLITE_NULL") panic("The column type is not one of SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB, or SQLITE_NULL")
} }
// ScanValues is like ScanValue on several columns. // ScanValues is like ScanValue on several columns.
func (s *Stmt) ScanValues(values []interface{}) { func (s *Stmt) ScanValues(values []interface{}) (err error) {
for i := range values { for i := range values {
values[i], _ = s.ScanValue(i, false) if values[i], _, err = s.ScanValue(i, false); err != nil {
break
}
} }
return
} }
// ScanText scans result value from a query. // ScanText scans result value from a query.
// The leftmost column/index is number 0. // The leftmost column/index is number 0.
// Returns true when column is null. // Returns true when column is null.
// (See sqlite3_column_text: http://sqlite.org/c3ref/column_blob.html) // (See sqlite3_column_text: http://sqlite.org/c3ref/column_blob.html)
func (s *Stmt) ScanText(index int) (value string, isNull bool) { func (s *Stmt) ScanText(index int) (value string, isNull bool, err error) {
if index < 0 || index >= s.ColumnCount() {
return "", false, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
p := C.sqlite3_column_text(s.stmt, C.int(index)) p := C.sqlite3_column_text(s.stmt, C.int(index))
if p == nil { if p == nil {
isNull = true isNull = true
...@@ -909,7 +928,10 @@ func (s *Stmt) ScanText(index int) (value string, isNull bool) { ...@@ -909,7 +928,10 @@ func (s *Stmt) ScanText(index int) (value string, isNull bool) {
// (See sqlite3_column_int: http://sqlite.org/c3ref/column_blob.html) // (See sqlite3_column_int: http://sqlite.org/c3ref/column_blob.html)
// TODO Factorize with ScanByte, ScanBool // TODO Factorize with ScanByte, ScanBool
func (s *Stmt) ScanInt(index int) (value int, isNull bool, err error) { func (s *Stmt) ScanInt(index int) (value int, isNull bool, err error) {
ctype := s.ColumnType(index) if index < 0 || index >= s.ColumnCount() {
return 0, false, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
ctype := s.columnType(index)
if ctype == Null { if ctype == Null {
isNull = true isNull = true
} else { } else {
...@@ -931,7 +953,10 @@ func (s *Stmt) ScanInt(index int) (value int, isNull bool, err error) { ...@@ -931,7 +953,10 @@ func (s *Stmt) ScanInt(index int) (value int, isNull bool, err error) {
// (See sqlite3_column_int: http://sqlite.org/c3ref/column_blob.html) // (See sqlite3_column_int: http://sqlite.org/c3ref/column_blob.html)
// TODO Factorize with ScanByte, ScanBool // TODO Factorize with ScanByte, ScanBool
func (s *Stmt) ScanInt32(index int) (value int32, isNull bool, err error) { func (s *Stmt) ScanInt32(index int) (value int32, isNull bool, err error) {
ctype := s.ColumnType(index) if index < 0 || index >= s.ColumnCount() {
return 0, false, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
ctype := s.columnType(index)
if ctype == Null { if ctype == Null {
isNull = true isNull = true
} else { } else {
...@@ -948,7 +973,10 @@ func (s *Stmt) ScanInt32(index int) (value int32, isNull bool, err error) { ...@@ -948,7 +973,10 @@ func (s *Stmt) ScanInt32(index int) (value int32, isNull bool, err error) {
// Returns true when column is null. // 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) {
ctype := s.ColumnType(index) if index < 0 || index >= s.ColumnCount() {
return 0, false, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
ctype := s.columnType(index)
if ctype == Null { if ctype == Null {
isNull = true isNull = true
} else { } else {
...@@ -965,7 +993,10 @@ func (s *Stmt) ScanInt64(index int) (value int64, isNull bool, err error) { ...@@ -965,7 +993,10 @@ func (s *Stmt) ScanInt64(index int) (value int64, isNull bool, err error) {
// Returns true when column is null. // 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) {
ctype := s.ColumnType(index) if index < 0 || index >= s.ColumnCount() {
return 0, false, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
ctype := s.columnType(index)
if ctype == Null { if ctype == Null {
isNull = true isNull = true
} else { } else {
...@@ -982,7 +1013,10 @@ func (s *Stmt) ScanByte(index int) (value byte, isNull bool, err error) { ...@@ -982,7 +1013,10 @@ func (s *Stmt) ScanByte(index int) (value byte, isNull bool, err error) {
// Returns true when column is null. // 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) {
ctype := s.ColumnType(index) if index < 0 || index >= s.ColumnCount() {
return false, false, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
ctype := s.columnType(index)
if ctype == Null { if ctype == Null {
isNull = true isNull = true
} else { } else {
...@@ -999,7 +1033,10 @@ func (s *Stmt) ScanBool(index int) (value bool, isNull bool, err error) { ...@@ -999,7 +1033,10 @@ func (s *Stmt) ScanBool(index int) (value bool, isNull bool, err error) {
// Returns true when column is null. // 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) {
ctype := s.ColumnType(index) if index < 0 || index >= s.ColumnCount() {
return 0, false, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
ctype := s.columnType(index)
if ctype == Null { if ctype == Null {
isNull = true isNull = true
} else { } else {
...@@ -1015,7 +1052,10 @@ func (s *Stmt) ScanDouble(index int) (value float64, isNull bool, err error) { ...@@ -1015,7 +1052,10 @@ func (s *Stmt) ScanDouble(index int) (value float64, isNull bool, err error) {
// The leftmost column/index is number 0. // The leftmost column/index is number 0.
// Returns true when column is null. // Returns true when column is null.
// (See sqlite3_column_blob: http://sqlite.org/c3ref/column_blob.html) // (See sqlite3_column_blob: http://sqlite.org/c3ref/column_blob.html)
func (s *Stmt) ScanBlob(index int) (value []byte, isNull bool) { func (s *Stmt) ScanBlob(index int) (value []byte, isNull bool, err error) {
if index < 0 || index >= s.ColumnCount() {
return nil, false, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
p := C.sqlite3_column_blob(s.stmt, C.int(index)) p := C.sqlite3_column_blob(s.stmt, C.int(index))
if p == nil { if p == nil {
isNull = true isNull = true
...@@ -1031,7 +1071,10 @@ func (s *Stmt) ScanBlob(index int) (value []byte, isNull bool) { ...@@ -1031,7 +1071,10 @@ func (s *Stmt) ScanBlob(index int) (value []byte, isNull bool) {
// The leftmost column/index is number 0. // The leftmost column/index is number 0.
// Returns true when column is null. // Returns true when column is null.
// (See sqlite3_column_blob: http://sqlite.org/c3ref/column_blob.html) // (See sqlite3_column_blob: http://sqlite.org/c3ref/column_blob.html)
func (s *Stmt) ScanRawBytes(index int) (value []byte, isNull bool) { func (s *Stmt) ScanRawBytes(index int) (value []byte, isNull bool, err error) {
if index < 0 || index >= s.ColumnCount() {
return nil, false, s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
}
p := C.sqlite3_column_blob(s.stmt, C.int(index)) p := C.sqlite3_column_blob(s.stmt, C.int(index))
if p == nil { if p == nil {
isNull = true isNull = true
...@@ -1049,7 +1092,11 @@ func (s *Stmt) ScanRawBytes(index int) (value []byte, isNull bool) { ...@@ -1049,7 +1092,11 @@ func (s *Stmt) ScanRawBytes(index int) (value []byte, isNull bool) {
// Returns true when column is null. // Returns true when column is null.
// The column type affinity must be consistent with the format used (INTEGER or NUMERIC or NONE for unix time, REAL or NONE for julian day). // The column type affinity must be consistent with the format used (INTEGER or NUMERIC or NONE for unix time, REAL or NONE for julian day).
func (s *Stmt) ScanTime(index int) (value time.Time, isNull bool, err error) { func (s *Stmt) ScanTime(index int) (value time.Time, isNull bool, err error) {
ctype := s.ColumnType(index) if index < 0 || index >= s.ColumnCount() {
err = s.specificError("column index %d out of range [0,%d[.", index, s.ColumnCount())
return
}
ctype := s.columnType(index)
switch ctype { switch ctype {
case Null: case Null:
isNull = true isNull = true
...@@ -1099,7 +1146,7 @@ func (s *Stmt) ScanTime(index int) (value time.Time, isNull bool, err error) { ...@@ -1099,7 +1146,7 @@ func (s *Stmt) ScanTime(index int) (value time.Time, isNull bool, err error) {
jd := float64(C.sqlite3_column_double(s.stmt, C.int(index))) jd := float64(C.sqlite3_column_double(s.stmt, C.int(index)))
value = JulianDayToLocalTime(jd) // local time value = JulianDayToLocalTime(jd) // local time
default: default:
s.specificError("unexpected column type affinity for time persistence: %q", ctype) err = s.specificError("unexpected column type affinity for time persistence: %q", ctype)
} }
return return
} }
......
...@@ -78,7 +78,8 @@ func TestInsertWithStatement(t *testing.T) { ...@@ -78,7 +78,8 @@ func TestInsertWithStatement(t *testing.T) {
defer checkFinalize(rs, t) defer checkFinalize(rs, t)
columnCount = rs.ColumnCount() columnCount = rs.ColumnCount()
assert.Equal(t, 3, columnCount, "column count") assert.Equal(t, 3, columnCount, "column count")
secondColumnName := rs.ColumnName(1) secondColumnName, err := rs.ColumnName(1)
checkNoError(t, err, "error accessing column name: %s")
assert.Equal(t, "int_num", secondColumnName, "column name") assert.Equal(t, "int_num", secondColumnName, "column name")
if checkStep(t, rs) { if checkStep(t, rs) {
...@@ -230,7 +231,8 @@ func TestScanNull(t *testing.T) { ...@@ -230,7 +231,8 @@ func TestScanNull(t *testing.T) {
assert.T(t, null, "expected null value") assert.T(t, null, "expected null value")
assert.Equal(t, false, bo, "expected false") assert.Equal(t, false, bo, "expected false")
rb, null := s.ScanRawBytes(0) rb, null, err := s.ScanRawBytes(0)
checkNoError(t, err, "scan error: %s")
assert.T(t, null, "expected null value") assert.T(t, null, "expected null value")
assert.Equal(t, 0, len(rb), "expected empty") assert.Equal(t, 0, len(rb), "expected empty")
} }
...@@ -254,7 +256,8 @@ func TestScanNotNull(t *testing.T) { ...@@ -254,7 +256,8 @@ func TestScanNotNull(t *testing.T) {
assert.T(t, !null, "expected not null value") assert.T(t, !null, "expected not null value")
assert.Equal(t, "1", *ps) assert.Equal(t, "1", *ps)
rb, null := s.ScanRawBytes(0) rb, null, err := s.ScanRawBytes(0)
checkNoError(t, err, "scan error: %s")
assert.T(t, !null, "expected not null value") assert.T(t, !null, "expected not null value")
assert.Equal(t, 1, len(rb), "expected not empty") assert.Equal(t, 1, len(rb), "expected not empty")
...@@ -509,7 +512,8 @@ func TestScanBytes(t *testing.T) { ...@@ -509,7 +512,8 @@ func TestScanBytes(t *testing.T) {
checkNoError(t, err, "prepare error: %s") checkNoError(t, err, "prepare error: %s")
defer checkFinalize(s, t) defer checkFinalize(s, t)
assert.T(t, checkStep(t, s)) assert.T(t, checkStep(t, s))
blob, _ := s.ScanBlob(0) blob, _, err := s.ScanBlob(0)
checkNoError(t, err, "scan error: %s")
assert.Equal(t, "test", string(blob)) assert.Equal(t, "test", string(blob))
} }
...@@ -528,9 +532,11 @@ func TestBindEmptyZero(t *testing.T) { ...@@ -528,9 +532,11 @@ func TestBindEmptyZero(t *testing.T) {
err = s.Scan(&ps, &zt) err = s.Scan(&ps, &zt)
checkNoError(t, err, "scan error: %s") checkNoError(t, err, "scan error: %s")
assert.T(t, ps == nil && zt.IsZero(), "null pointers expected") assert.T(t, ps == nil && zt.IsZero(), "null pointers expected")
_, null := s.ScanValue(0, false) _, null, err := s.ScanValue(0, false)
checkNoError(t, err, "scan error: %s")
assert.T(t, null, "null string expected") assert.T(t, null, "null string expected")
_, null = s.ScanValue(1, false) _, null, err = s.ScanValue(1, false)
checkNoError(t, err, "scan error: %s")
assert.T(t, null, "null time expected") assert.T(t, null, "null time expected")
} }
...@@ -556,9 +562,11 @@ func TestBindEmptyZeroNotTransformedToNull(t *testing.T) { ...@@ -556,9 +562,11 @@ func TestBindEmptyZeroNotTransformedToNull(t *testing.T) {
err = s.Scan(&st, &zt) err = s.Scan(&st, &zt)
checkNoError(t, err, "scan error: %s") checkNoError(t, err, "scan error: %s")
assert.T(t, len(st) == 0 && zt.IsZero(), "null pointers expected") assert.T(t, len(st) == 0 && zt.IsZero(), "null pointers expected")
_, null := s.ScanValue(0, false) _, null, err := s.ScanValue(0, false)
checkNoError(t, err, "scan error: %s")
assert.T(t, !null, "empty string expected") assert.T(t, !null, "empty string expected")
_, null = s.ScanValue(1, false) _, null, err = s.ScanValue(1, false)
checkNoError(t, err, "scan error: %s")
assert.T(t, !null, "zero time expected") assert.T(t, !null, "zero time expected")
} }
...@@ -574,8 +582,12 @@ func TestColumnType(t *testing.T) { ...@@ -574,8 +582,12 @@ func TestColumnType(t *testing.T) {
expectedAffinities := []Affinity{Integral, Real, Integral, Textual} expectedAffinities := []Affinity{Integral, Real, Integral, Textual}
for col := 0; col < s.ColumnCount(); col++ { for col := 0; col < s.ColumnCount(); col++ {
//println(col, s.ColumnName(col), s.ColumnOriginName(col), s.ColumnType(col), s.ColumnDeclaredType(col)) //println(col, s.ColumnName(col), s.ColumnOriginName(col), s.ColumnType(col), s.ColumnDeclaredType(col))
assert.Equal(t, Null, s.ColumnType(col), "column type") ct, err := s.ColumnType(col)
assert.Equal(t, expectedAffinities[col], s.ColumnTypeAffinity(col), "column type affinity") checkNoError(t, err, "column type error: %s")
assert.Equal(t, Null, ct, "column type")
cta, err := s.ColumnTypeAffinity(col)
checkNoError(t, err, "column type affinity error: %s")
assert.Equal(t, expectedAffinities[col], cta, "column type affinity")
} }
} }
......
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