// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package sqlite /* #include <sqlite3.h> #include <stdlib.h> #include <string.h> // These wrappers are necessary because SQLITE_TRANSIENT // is a pointer constant, and cgo doesn't translate them correctly. // The definition in sqlite3.h is: // // typedef void (*sqlite3_destructor_type)(void*); // #define SQLITE_STATIC ((sqlite3_destructor_type)0) // #define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1) static int my_bind_text(sqlite3_stmt *stmt, int n, const char *p, int np) { return sqlite3_bind_text(stmt, n, p, np, SQLITE_TRANSIENT); } static int my_bind_blob(sqlite3_stmt *stmt, int n, void *p, int np) { return sqlite3_bind_blob(stmt, n, p, np, SQLITE_TRANSIENT); } // just to get ride of "warning: passing argument 5 of ‘sqlite3_prepare_v2’ from incompatible pointer type [...] ‘const char **’ but argument is of type ‘char **’" static int my_prepare_v2(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, char **pzTail) { return sqlite3_prepare_v2(db, zSql, nByte, ppStmt, (const char**)pzTail); } */ import "C" import ( "database/sql" "database/sql/driver" "errors" "fmt" "math" "reflect" "time" "unsafe" ) type StmtError struct { ConnError s *Stmt } // SQL returns the SQL associated with the prepared statement in error. func (e *StmtError) SQL() string { return e.s.SQL() } func (s *Stmt) error(rv C.int, details ...string) error { if s == nil { return errors.New("nil sqlite statement") } if rv == C.SQLITE_OK { return nil } err := ConnError{c: s.c, code: Errno(rv), msg: C.GoString(C.sqlite3_errmsg(s.c.db))} if len(details) > 0 { err.details = details[0] } return &StmtError{err, s} } func (s *Stmt) specificError(msg string, a ...interface{}) error { return &StmtError{ConnError{c: s.c, code: ErrSpecific, msg: fmt.Sprintf(msg, a...)}, s} } // SQL statement // (See http://sqlite.org/c3ref/stmt.html) type Stmt struct { c *Conn stmt *C.sqlite3_stmt sql string tail string columnCount int cols map[string]int // cached columns index by name bindParameterCount int params map[string]int // cached parameter index by name // Enable type check in Scan methods (default true) CheckTypeMismatch bool // Tell if the stmt should be cached (default true) Cacheable bool } func (c *Conn) prepare(cmd string, args ...interface{}) (*Stmt, error) { if c == nil { return nil, errors.New("nil sqlite database") } cmdstr := C.CString(cmd) defer C.free(unsafe.Pointer(cmdstr)) var stmt *C.sqlite3_stmt var tail *C.char // If the caller knows that the supplied string is nul-terminated, then there is a small performance advantage to be gained by passing an nByte parameter that is equal to the number of bytes in the input string including the nul-terminator bytes as this saves SQLite from having to make a copy of the input string. rv := C.my_prepare_v2(c.db, cmdstr, C.int(len(cmd)+1), &stmt, &tail) if rv != C.SQLITE_OK { return nil, c.error(rv, cmd) } var t string if tail != nil && C.strlen(tail) > 0 { t = C.GoString(tail) } s := &Stmt{c: c, stmt: stmt, tail: t, columnCount: -1, bindParameterCount: -1, CheckTypeMismatch: true} if len(args) > 0 { err := s.Bind(args...) if err != nil { s.finalize() return nil, err } } return s, nil } // Prepare first looks in the statement cache or compiles the SQL statement. // And optionally bind values. // (See sqlite3_prepare_v2: http://sqlite.org/c3ref/prepare.html) func (c *Conn) Prepare(cmd string, args ...interface{}) (*Stmt, error) { s := c.stmtCache.find(cmd) if s != nil { if len(args) > 0 { err := s.Bind(args...) if err != nil { s.finalize() // don't put it back in the cache return nil, err } } return s, nil } s, err := c.prepare(cmd, args...) if s != nil { s.Cacheable = true } return s, err } // Exec is a one-step statement execution. // Don't use it with SELECT or anything that returns data. // The Stmt is reset at each call. // (See http://sqlite.org/c3ref/bind_blob.html, http://sqlite.org/c3ref/step.html) func (s *Stmt) Exec(args ...interface{}) error { // TODO Check column count == 0 err := s.Bind(args...) if err != nil { return err } return s.exec() } func (s *Stmt) exec() error { rv := C.sqlite3_step(s.stmt) C.sqlite3_reset(s.stmt) err := Errno(rv) if err != Done { if err == Row { return s.error(rv, "Don't use exec with anything that returns data such as SELECT") } return s.error(rv, "Stmt.exec") } return nil } // ExecDml is 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. // The Stmt is reset at each call. func (s *Stmt) ExecDml(args ...interface{}) (int, error) { err := s.Exec(args...) if err != nil { return -1, err } return s.c.Changes(), nil } // Insert is like ExecDml but returns the autoincremented rowid. // Don't use it with SELECT or anything that returns data. // The Stmt is reset at each call. func (s *Stmt) Insert(args ...interface{}) (int64, error) { n, err := s.ExecDml(args...) if err != nil { return -1, err } if n == 0 { // No change => no insert... return -1, nil } return s.c.LastInsertRowid(), nil } // Select helps executing SELECT statement: // (1) it binds the specified args, // (2) it steps on the rows returned, // (3) it delegates scanning to a callback function. // The callback function is invoked for each result row coming out of the statement. // // s, err := db.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, args ...interface{}) error { if len(args) > 0 { err := s.Bind(args...) if err != nil { return err } } for { if ok, err := s.Next(); err != nil { return err } else if !ok { break } if err := rowCallbackHandler(s); err != nil { return err } } return nil } // SelectOneRow helps executing SELECT statement that is expected to return only one row. // Args are for scanning (not binding). // Returns false if there is no matching row. // No check is done to ensure that no more than one row is returned by the statement. // TODO Create a SelectUniqueRow that checks that the row is unique. func (s *Stmt) SelectOneRow(args ...interface{}) (bool, error) { if ok, err := s.Next(); err != nil { return false, err } else if !ok { return false, nil } return true, s.Scan(args...) } // BindParameterCount returns the number of SQL parameters. // FIXME If parameters of the ?NNN form are used, there may be gaps in the list. // (See http://sqlite.org/c3ref/bind_parameter_count.html) func (s *Stmt) BindParameterCount() int { if s.bindParameterCount == -1 { s.bindParameterCount = int(C.sqlite3_bind_parameter_count(s.stmt)) } return s.bindParameterCount } // BindParameterIndex returns the index of a parameter with a given name (cached). // The first host parameter has an index of 1, not 0. // (See http://sqlite.org/c3ref/bind_parameter_index.html) func (s *Stmt) BindParameterIndex(name string) (int, error) { if s.params == nil { count := s.BindParameterCount() s.params = make(map[string]int, count) } index, ok := s.params[name] if ok { return index, nil } cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) index = int(C.sqlite3_bind_parameter_index(s.stmt, cname)) if index == 0 { return index, s.specificError("invalid parameter name: %q", name) } s.params[name] = index return index, nil } // BindParameterName returns the name of a wildcard parameter (not cached). // Returns "" if the index is out of range or if the wildcard is unnamed. // The first host parameter has an index of 1, not 0. // (See http://sqlite.org/c3ref/bind_parameter_name.html) func (s *Stmt) BindParameterName(i int) (string, error) { name := C.sqlite3_bind_parameter_name(s.stmt, C.int(i)) if name == nil { return "", s.specificError("invalid parameter index: %d", i) } return C.GoString(name), nil } // NamedBind binds parameters by their name (name1, value1, ...) func (s *Stmt) NamedBind(args ...interface{}) error { if len(args)%2 != 0 { return s.specificError("expected an even number of arguments: %d", len(args)) } for i := 0; i < len(args); i += 2 { name, ok := args[i].(string) if !ok { return s.specificError("non-string param name at %d: %T", i, args[i]) } index, err := s.BindParameterIndex(name) // How to look up only once for one statement ? if err != nil { return err } err = s.BindByIndex(index, args[i+1]) if err != nil { return err } } return nil } // Bind binds parameters by their index. // Calls sqlite3_bind_parameter_count and sqlite3_bind_(blob|double|int|int64|null|text) depending on args type/kind. // (See http://sqlite.org/c3ref/bind_blob.html) func (s *Stmt) Bind(args ...interface{}) error { n := s.BindParameterCount() if n != len(args) { return s.specificError("incorrect argument count for Stmt.Bind: have %d want %d", len(args), n) } for i, v := range args { err := s.BindByIndex(i+1, v) if err != nil { return err } } return nil } // NullIfEmpty transforms empty string to null when true (true by default) var NullIfEmptyString = true // NullIfZeroTime transforms zero time (time.Time.IsZero) to null when true (true by default) var NullIfZeroTime = true // BindByIndex binds value to the specified host parameter of the prepared statement. // Value's type/kind is used to find the storage class. // The leftmost SQL parameter has an index of 1. func (s *Stmt) BindByIndex(index int, value interface{}) error { i := C.int(index) var rv C.int switch value := value.(type) { case nil: rv = C.sqlite3_bind_null(s.stmt, i) case string: if NullIfEmptyString && len(value) == 0 { rv = C.sqlite3_bind_null(s.stmt, i) } else { cs, l := cstring(value) rv = C.my_bind_text(s.stmt, i, cs, l) } case int: rv = C.sqlite3_bind_int(s.stmt, i, C.int(value)) case int64: rv = C.sqlite3_bind_int64(s.stmt, i, C.sqlite3_int64(value)) case byte: rv = C.sqlite3_bind_int(s.stmt, i, C.int(value)) case bool: rv = C.sqlite3_bind_int(s.stmt, i, btocint(value)) case float32: rv = C.sqlite3_bind_double(s.stmt, i, C.double(value)) case float64: rv = C.sqlite3_bind_double(s.stmt, i, C.double(value)) case []byte: var p *byte if len(value) > 0 { p = &value[0] } rv = C.my_bind_blob(s.stmt, i, unsafe.Pointer(p), C.int(len(value))) case time.Time: if NullIfZeroTime && value.IsZero() { rv = C.sqlite3_bind_null(s.stmt, i) } else { rv = C.sqlite3_bind_int64(s.stmt, i, C.sqlite3_int64(value.Unix())) } case ZeroBlobLength: rv = C.sqlite3_bind_zeroblob(s.stmt, i, C.int(value)) case driver.Valuer: v, err := value.Value() if err != nil { return err } return s.BindByIndex(index, v) default: return s.BindReflect(index, value) } return s.error(rv, "Stmt.Bind") } // BindReflect binds value to the specified host parameter of the prepared statement. // Value's (reflect) Kind is used to find the storage class. // The leftmost SQL parameter has an index of 1. func (s *Stmt) BindReflect(index int, value interface{}) error { i := C.int(index) var rv C.int v := reflect.ValueOf(value) switch v.Kind() { case reflect.String: cs, l := cstring(v.String()) rv = C.my_bind_text(s.stmt, i, cs, l) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: rv = C.sqlite3_bind_int64(s.stmt, i, C.sqlite3_int64(v.Int())) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: ui := v.Uint() if ui > math.MaxInt64 { return s.specificError("int overflow") } rv = C.sqlite3_bind_int64(s.stmt, i, C.sqlite3_int64(ui)) case reflect.Bool: rv = C.sqlite3_bind_int(s.stmt, i, btocint(v.Bool())) case reflect.Float32, reflect.Float64: rv = C.sqlite3_bind_double(s.stmt, i, C.double(v.Float())) default: name, _ := s.BindParameterName(index) return s.specificError("unsupported type in Bind: %T (index: %d, name: %q)", value, index, name) } return s.error(rv, "Stmt.Bind") } // Next evaluates an SQL statement // // With custom error handling: // for { // if ok, err := s.Next(); err != nil { // return nil, err // } else if !ok { // break // } // err = s.Scan(&fnum, &inum, &sstr) // } // With panic on error: // for Must(s.Next()) { // err := s.Scan(&fnum, &inum, &sstr) // } // // (See http://sqlite.org/c3ref/step.html) func (s *Stmt) Next() (bool, error) { rv := C.sqlite3_step(s.stmt) err := Errno(rv) if err == Row { return true, nil } C.sqlite3_reset(s.stmt) // Release implicit lock as soon as possible (see dbEvalStep in tclsqlite3.c) if err != Done { return false, s.error(rv, "Stmt.Next") } // TODO Check column count > 0 return false, nil } // Reset terminates the current execution of an SQL statement // and reset it back to its starting state so that it can be reused. // (See http://sqlite.org/c3ref/reset.html) func (s *Stmt) Reset() error { return s.error(C.sqlite3_reset(s.stmt), "Stmt.Reset") } // ClearBindings resets all bindings on a prepared statement. // (See http://sqlite.org/c3ref/clear_bindings.html) func (s *Stmt) ClearBindings() error { return s.error(C.sqlite3_clear_bindings(s.stmt), "Stmt.ClearBindings") } // ColumnCount returns the number of columns in the result set for the statement (with or without row). // (See http://sqlite.org/c3ref/column_count.html) func (s *Stmt) ColumnCount() int { if s.columnCount == -1 { s.columnCount = int(C.sqlite3_column_count(s.stmt)) } return s.columnCount } // DataCount returns the number of values available from the current row of the currently executing statement. // Same as ColumnCount() except when there is no (more) row, it returns 0. // (See http://sqlite.org/c3ref/data_count.html) func (s *Stmt) DataCount() int { return int(C.sqlite3_data_count(s.stmt)) } // 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. // (See http://sqlite.org/c3ref/column_name.html) func (s *Stmt) ColumnName(index int) string { // 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))) } // ColumnNames returns the name of the columns of the result set returned by the SQL statement. (not cached) func (s *Stmt) ColumnNames() []string { count := s.ColumnCount() names := make([]string, count) for i := 0; i < count; i++ { names[i] = s.ColumnName(i) } return names } // SQLite fundamental datatypes type Type int func (t Type) String() string { return typeText[t] } const ( Integer = Type(C.SQLITE_INTEGER) Float = Type(C.SQLITE_FLOAT) Blob = Type(C.SQLITE_BLOB) Null = Type(C.SQLITE_NULL) Text = Type(C.SQLITE3_TEXT) ) var typeText = map[Type]string{ Integer: "Integer", Float: "Float", Blob: "Blob", Null: "Null", Text: "Text", } // ColumnType returns the datatype code for the initial data type of the result column. // 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. // (See sqlite3_column_type: http://sqlite.org/c3ref/column_blob.html) 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, ...). // // 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. // To avoid NULL conversion, arg type must be **T. // Calls sqlite3_column_(blob|double|int|int64|text) depending on args type. // (See http://sqlite.org/c3ref/column_blob.html) func (s *Stmt) NamedScan(args ...interface{}) error { if len(args)%2 != 0 { return s.specificError("expected an even number of arguments: %d", len(args)) } for i := 0; i < len(args); i += 2 { name, ok := args[i].(string) if !ok { return s.specificError("non-string field name at %d: %T", i, args[i]) } 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.ScanByIndex(index, ptr) if err != nil { return err } } return nil } // Scan scans result values from a query. // // 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. // To avoid NULL conversion, arg type must be **T. // Calls sqlite3_column_(blob|double|int|int64|text) depending on args type/kind. // (See http://sqlite.org/c3ref/column_blob.html) func (s *Stmt) Scan(args ...interface{}) error { n := s.ColumnCount() if n != len(args) { // What happens when the number of arguments is less than the number of columns? return s.specificError("incorrect argument count for Stmt.Scan: have %d want %d", len(args), n) } for i, v := range args { _, err := s.ScanByIndex(i, v) if err != nil { return err } } return nil } // SQL returns the SQL associated with a prepared statement. // (See http://sqlite.org/c3ref/sql.html) func (s *Stmt) SQL() string { if s.sql == "" { s.sql = C.GoString(C.sqlite3_sql(s.stmt)) } return s.sql } // ColumnIndex returns the column index in a result set for a given column name. // The leftmost column is number 0. // Must scan all columns (but result is cached). // (See http://sqlite.org/c3ref/column_name.html) func (s *Stmt) ColumnIndex(name string) (int, error) { if s.cols == nil { count := s.ColumnCount() s.cols = make(map[string]int, count) for i := 0; i < count; i++ { s.cols[s.ColumnName(i)] = i } } index, ok := s.cols[name] if ok { return index, nil } return -1, s.specificError("invalid column name: %s", name) } // ScanByName scans result value from a query. // Returns true when column is null. // Calls sqlite3_column_(blob|double|int|int64|text) depending on arg type/kind. // (See http://sqlite.org/c3ref/column_blob.html) func (s *Stmt) ScanByName(name string, value interface{}) (bool, error) { index, err := s.ColumnIndex(name) if err != nil { return false, err } return s.ScanByIndex(index, value) } // ScanByIndex scans result value from a query. // The leftmost column/index is number 0. // // Destination type is specified by the caller (except when value type is *interface{}). // The value must be of one of the following types/kinds: // (*)*string // (*)*int,int8,int16,int32,int64 // (*)*uint,uint8,uint16,uint32,uint64 // (*)*bool // (*)*float32,float64 // (*)*[]byte // *time.Time // sql.Scanner // *interface{} // // Returns true when column is null. // Calls sqlite3_column_(blob|double|int|int64|text) depending on arg type/kind. // (See http://sqlite.org/c3ref/column_blob.html) func (s *Stmt) ScanByIndex(index int, value interface{}) (bool, error) { var isNull bool var err error switch value := value.(type) { case nil: case *string: *value, isNull = s.ScanText(index) case **string: var st string st, isNull = s.ScanText(index) if isNull { *value = nil } else { **value = st } case *int: *value, isNull, err = s.ScanInt(index) case **int: var i int i, isNull, err = s.ScanInt(index) if err == nil { if isNull { *value = nil } else { **value = i } } case *int64: *value, isNull, err = s.ScanInt64(index) case **int64: var i int64 i, isNull, err = s.ScanInt64(index) if err == nil { if isNull { *value = nil } else { **value = i } } case *byte: *value, isNull, err = s.ScanByte(index) case **byte: var b byte b, isNull, err = s.ScanByte(index) if err == nil { if isNull { *value = nil } else { **value = b } } case *bool: *value, isNull, err = s.ScanBool(index) case **bool: var b bool b, isNull, err = s.ScanBool(index) if err == nil { if isNull { *value = nil } else { **value = b } } case *float64: *value, isNull, err = s.ScanDouble(index) case **float64: var f float64 f, isNull, err = s.ScanDouble(index) if err == nil { if isNull { *value = nil } else { **value = f } } case *[]byte: *value, isNull = s.ScanBlob(index) case **[]byte: var bs []byte bs, isNull = s.ScanBlob(index) if isNull { *value = nil } else { **value = bs } case *time.Time: // go fix doesn't like this type! *value, isNull, err = s.ScanTime(index) case sql.Scanner: var v interface{} v, isNull = s.ScanValue(index, false) err = value.Scan(v) case *interface{}: *value, isNull = s.ScanValue(index, false) default: return s.ScanReflect(index, value) } return isNull, err } // ScanReflect scans result value from a query. // The leftmost column/index is number 0. // // Destination type is specified by the caller. // The value must be of one of the following kinds: // *string // *int,int8,int16,int32,int64 // *uint,uint8,uint16,uint32,uint64 // *bool // *float32,float64 // // Returns true when column is null. func (s *Stmt) ScanReflect(index int, v interface{}) (bool, error) { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Ptr || rv.IsNil() { return false, s.specificError("ScanReflect unsupported type %T", v) } var isNull bool var err error dv := reflect.Indirect(rv) switch dv.Kind() { case reflect.String: var t string t, isNull = s.ScanText(index) dv.SetString(t) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: var i int64 i, isNull, err = s.ScanInt64(index) if err == nil { dv.SetInt(i) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: var i int64 i, isNull, err = s.ScanInt64(index) if err == nil { if i < 0 { err = s.specificError("negative value: %d", i) } else { dv.SetUint(uint64(i)) } } case reflect.Bool: var b bool b, isNull, err = s.ScanBool(index) if err == nil { dv.SetBool(b) } case reflect.Float32, reflect.Float64: var f float64 f, isNull, err = s.ScanDouble(index) if err == nil { dv.SetFloat(f) } default: return false, s.specificError("unsupported type in Scan: %T", v) } return isNull, err } // ScanValue scans result value from a query. // 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 (exception if blob is true) // int64 // float64 // []byte // // Calls sqlite3_column_(blob|double|int|int64|text) depending on columns type. // (See http://sqlite.org/c3ref/column_blob.html) func (s *Stmt) ScanValue(index int, blob bool) (interface{}, bool) { switch s.ColumnType(index) { case Null: return nil, true case Text: if blob { p := C.sqlite3_column_blob(s.stmt, C.int(index)) n := C.sqlite3_column_bytes(s.stmt, C.int(index)) return C.GoBytes(p, n), false } p := C.sqlite3_column_text(s.stmt, C.int(index)) return C.GoString((*C.char)(unsafe.Pointer(p))), false case Integer: return int64(C.sqlite3_column_int64(s.stmt, C.int(index))), false case Float: return float64(C.sqlite3_column_double(s.stmt, C.int(index))), false case Blob: p := C.sqlite3_column_blob(s.stmt, C.int(index)) n := C.sqlite3_column_bytes(s.stmt, C.int(index)) // 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. } 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. func (s *Stmt) ScanValues(values []interface{}) { for i := range values { values[i], _ = s.ScanValue(i, false) } } // ScanText scans result value from a query. // The leftmost column/index is number 0. // Returns true when column is null. // (See sqlite3_column_text: http://sqlite.org/c3ref/column_blob.html) func (s *Stmt) ScanText(index int) (value string, isNull bool) { p := C.sqlite3_column_text(s.stmt, C.int(index)) if p == nil { isNull = true } else { value = C.GoString((*C.char)(unsafe.Pointer(p))) } return } // ScanInt scans result value from a query. // The leftmost column/index is number 0. // Returns true when column is null. // (See sqlite3_column_int: http://sqlite.org/c3ref/column_blob.html) // TODO Factorize with ScanByte, ScanBool func (s *Stmt) ScanInt(index int) (value int, isNull bool, err error) { ctype := s.ColumnType(index) if ctype == Null { isNull = true } else { if s.CheckTypeMismatch { err = s.checkTypeMismatch(ctype, Integer) } value = int(C.sqlite3_column_int(s.stmt, C.int(index))) } return } // ScanInt64 scans result value from a query. // The leftmost column/index is number 0. // Returns true when column is null. // (See sqlite3_column_int64: http://sqlite.org/c3ref/column_blob.html) func (s *Stmt) ScanInt64(index int) (value int64, isNull bool, err error) { ctype := s.ColumnType(index) if ctype == Null { isNull = true } else { if s.CheckTypeMismatch { err = s.checkTypeMismatch(ctype, Integer) } value = int64(C.sqlite3_column_int64(s.stmt, C.int(index))) } return } // ScanByte scans result value from a query. // The leftmost column/index is number 0. // Returns true when column is null. // (See sqlite3_column_int: http://sqlite.org/c3ref/column_blob.html) func (s *Stmt) ScanByte(index int) (value byte, isNull bool, err error) { ctype := s.ColumnType(index) if ctype == Null { isNull = true } else { if s.CheckTypeMismatch { err = s.checkTypeMismatch(ctype, Integer) } value = byte(C.sqlite3_column_int(s.stmt, C.int(index))) } return } // ScanBool scans result value from a query. // The leftmost column/index is number 0. // Returns true when column is null. // (See sqlite3_column_int: http://sqlite.org/c3ref/column_blob.html) func (s *Stmt) ScanBool(index int) (value bool, isNull bool, err error) { ctype := s.ColumnType(index) if ctype == Null { isNull = true } else { if s.CheckTypeMismatch { err = s.checkTypeMismatch(ctype, Integer) } value = C.sqlite3_column_int(s.stmt, C.int(index)) == 1 } return } // ScanDouble scans result value from a query. // The leftmost column/index is number 0. // Returns true when column is null. // (See sqlite3_column_double: http://sqlite.org/c3ref/column_blob.html) func (s *Stmt) ScanDouble(index int) (value float64, isNull bool, err error) { ctype := s.ColumnType(index) if ctype == Null { isNull = true } else { if s.CheckTypeMismatch { err = s.checkTypeMismatch(ctype, Float) } value = float64(C.sqlite3_column_double(s.stmt, C.int(index))) } return } // ScanBlob scans result value from a query. // The leftmost column/index is number 0. // Returns true when column is null. // (See sqlite3_column_blob: http://sqlite.org/c3ref/column_blob.html) func (s *Stmt) ScanBlob(index int) (value []byte, isNull bool) { p := C.sqlite3_column_blob(s.stmt, C.int(index)) if p == nil { isNull = true } else { n := C.sqlite3_column_bytes(s.stmt, C.int(index)) // value = (*[1 << 30]byte)(unsafe.Pointer(p))[:n] value = C.GoBytes(p, n) // The memory space used to hold strings and BLOBs is freed automatically. } return } // ScanTime scans result value from a query. // If time is persisted as string without timezone, UTC is used. // If time is persisted as numeric, local is used. // The leftmost column/index is number 0. // Returns true when column is null. func (s *Stmt) ScanTime(index int) (value time.Time, isNull bool, err error) { switch s.ColumnType(index) { case Null: isNull = true case Text: p := C.sqlite3_column_text(s.stmt, C.int(index)) txt := C.GoString((*C.char)(unsafe.Pointer(p))) var layout string switch len(txt) { case 5: // HH:MM layout = "15:04" case 8: // HH:MM:SS layout = "15:04:05" case 10: // YYYY-MM-DD layout = "2006-01-02" case 12: // HH:MM:SS.SSS layout = "15:04:05.000" case 16: // YYYY-MM-DDTHH:MM if txt[10] == 'T' { layout = "2006-01-02T15:04" } else { layout = "2006-01-02 15:04" } case 19: // YYYY-MM-DDTHH:MM:SS if txt[10] == 'T' { layout = "2006-01-02T15:04:05" } else { layout = "2006-01-02 15:04:05" } case 23: // YYYY-MM-DDTHH:MM:SS.SSS if txt[10] == 'T' { layout = "2006-01-02T15:04:05.999" } else { layout = "2006-01-02 15:04:05.999" } default: // YYYY-MM-DDTHH:MM:SS.SSSZhh:mm or parse error if len(txt) > 10 && txt[10] == 'T' { layout = "2006-01-02T15:04:05.999Z07:00" } else { layout = "2006-01-02 15:04:05.999Z07:00" } } value, err = time.Parse(layout, txt) // UTC except when timezone is specified case Integer: unixepoch := int64(C.sqlite3_column_int64(s.stmt, C.int(index))) value = time.Unix(unixepoch, 0) // local time case Float: jd := float64(C.sqlite3_column_double(s.stmt, C.int(index))) value = JulianDayToLocalTime(jd) // local time default: panic("The column type is not one of SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, or SQLITE_NULL") } return } // Only lossy conversion is reported as error. func (s *Stmt) checkTypeMismatch(source, target Type) error { switch target { case Integer: switch source { case Float: fallthrough case Text: fallthrough case Blob: return s.specificError("type mismatch, source %s vs target %s", source, target) } case Float: switch source { case Text: fallthrough case Blob: return s.specificError("type mismatch, source %s vs target %s", source, target) } } return nil } // Busy returns true if the prepared statement is in need of being reset. // (See http://sqlite.org/c3ref/stmt_busy.html) func (s *Stmt) Busy() bool { return C.sqlite3_stmt_busy(s.stmt) != 0 } // Finalize destroys a prepared statement. // (See http://sqlite.org/c3ref/finalize.html) func (s *Stmt) Finalize() error { if s == nil { return errors.New("nil sqlite statement") } if s.Cacheable && s.c != nil && s.c.db != nil { return s.c.stmtCache.release(s) } return s.finalize() } func (s *Stmt) finalize() error { if s == nil { return errors.New("nil sqlite statement") } if s.stmt == nil { return nil } if s.c == nil || s.c.db == nil { Log(C.SQLITE_MISUSE, "sqlite statement with already closed database connection") return errors.New("sqlite statement with already closed database connection") } rv := C.sqlite3_finalize(s.stmt) if rv != C.SQLITE_OK { Log(int(rv), "error while finalizing Stmt") return s.error(rv, "Stmt.finalize") } s.stmt = nil return nil } // Conn finds the database handle of a prepared statement. // (Like http://sqlite.org/c3ref/db_handle.html) func (s *Stmt) Conn() *Conn { return s.c } // ReadOnly returns true if the prepared statement is guaranteed to not modify the database. // (See http://sqlite.org/c3ref/stmt_readonly.html) func (s *Stmt) ReadOnly() bool { return C.sqlite3_stmt_readonly(s.stmt) == 1 }