Wrap value.

This commit is contained in:
Nuno Cruces
2023-06-30 10:45:16 +01:00
parent 6a982559cd
commit a6c2fccd74
3 changed files with 149 additions and 16 deletions

View File

@@ -156,6 +156,12 @@ func newModule(mod api.Module) (m *module, err error) {
lastRowid: getFun("sqlite3_last_insert_rowid"), lastRowid: getFun("sqlite3_last_insert_rowid"),
autocommit: getFun("sqlite3_get_autocommit"), autocommit: getFun("sqlite3_get_autocommit"),
createCollation: getFun("sqlite3_create_go_collation"), createCollation: getFun("sqlite3_create_go_collation"),
valueType: getFun("sqlite3_value_type"),
valueInteger: getFun("sqlite3_value_int64"),
valueFloat: getFun("sqlite3_value_double"),
valueText: getFun("sqlite3_value_text"),
valueBlob: getFun("sqlite3_value_blob"),
valueBytes: getFun("sqlite3_value_bytes"),
} }
if err != nil { if err != nil {
return nil, err return nil, err
@@ -352,5 +358,11 @@ type sqliteAPI struct {
lastRowid api.Function lastRowid api.Function
autocommit api.Function autocommit api.Function
createCollation api.Function createCollation api.Function
valueType api.Function
valueInteger api.Function
valueFloat api.Function
valueText api.Function
valueBlob api.Function
valueBytes api.Function
destructor uint32 destructor uint32
} }

22
stmt.go
View File

@@ -374,18 +374,7 @@ func (s *Stmt) ColumnBlob(col int, buf []byte) []byte {
func (s *Stmt) ColumnRawText(col int) []byte { func (s *Stmt) ColumnRawText(col int) []byte {
r := s.c.call(s.c.api.columnText, r := s.c.call(s.c.api.columnText,
uint64(s.handle), uint64(col)) uint64(s.handle), uint64(col))
return s.columnRawBytes(col, uint32(r))
ptr := uint32(r)
if ptr == 0 {
r = s.c.call(s.c.api.errcode, uint64(s.c.handle))
s.err = s.c.error(r)
return nil
}
r = s.c.call(s.c.api.columnBytes,
uint64(s.handle), uint64(col))
return util.View(s.c.mod, ptr, r)
} }
// ColumnRawBlob returns the value of the result column as a []byte. // ColumnRawBlob returns the value of the result column as a []byte.
@@ -397,17 +386,18 @@ func (s *Stmt) ColumnRawText(col int) []byte {
func (s *Stmt) ColumnRawBlob(col int) []byte { func (s *Stmt) ColumnRawBlob(col int) []byte {
r := s.c.call(s.c.api.columnBlob, r := s.c.call(s.c.api.columnBlob,
uint64(s.handle), uint64(col)) uint64(s.handle), uint64(col))
return s.columnRawBytes(col, uint32(r))
}
ptr := uint32(r) func (s *Stmt) columnRawBytes(col int, ptr uint32) []byte {
if ptr == 0 { if ptr == 0 {
r = s.c.call(s.c.api.errcode, uint64(s.c.handle)) r := s.c.call(s.c.api.errcode, uint64(s.c.handle))
s.err = s.c.error(r) s.err = s.c.error(r)
return nil return nil
} }
r = s.c.call(s.c.api.columnBytes, r := s.c.call(s.c.api.columnBytes,
uint64(s.handle), uint64(col)) uint64(s.handle), uint64(col))
return util.View(s.c.mod, ptr, r) return util.View(s.c.mod, ptr, r)
} }

131
value.go Normal file
View File

@@ -0,0 +1,131 @@
package sqlite3
import (
"math"
"time"
"github.com/ncruces/go-sqlite3/internal/util"
)
// Value is any value that can be stored in a database table.
//
// https://www.sqlite.org/c3ref/value.html
type Value struct {
c *Conn
handle uint32
}
// Type returns the initial [Datatype] of the value.
//
// https://www.sqlite.org/c3ref/value_blob.html
func (v *Value) Type() Datatype {
r := v.c.call(v.c.api.valueType, uint64(v.handle))
return Datatype(r)
}
// Bool returns the value as a bool.
// SQLite does not have a separate boolean storage class.
// Instead, boolean values are retrieved as integers,
// with 0 converted to false and any other value to true.
//
// https://www.sqlite.org/c3ref/value_blob.html
func (v *Value) Bool() bool {
if i := v.Int64(); i != 0 {
return true
}
return false
}
// Int returns the value as an int.
//
// https://www.sqlite.org/c3ref/value_blob.html
func (v *Value) Int() int {
return int(v.Int64())
}
// Int64 returns the value as an int64.
//
// https://www.sqlite.org/c3ref/value_blob.html
func (v *Value) Int64() int64 {
r := v.c.call(v.c.api.valueInteger, uint64(v.handle))
return int64(r)
}
// Float returns the value as a float64.
//
// https://www.sqlite.org/c3ref/value_blob.html
func (v *Value) Float() float64 {
r := v.c.call(v.c.api.valueFloat, uint64(v.handle))
return math.Float64frombits(r)
}
// Time returns the value as a [time.Time].
//
// https://www.sqlite.org/c3ref/value_blob.html
func (v *Value) Time(format TimeFormat) (time.Time, error) {
var t any
var err error
switch v.Type() {
case INTEGER:
t = v.Int64()
case FLOAT:
t = v.Float()
case TEXT, BLOB:
t, err = v.Text()
if err != nil {
return time.Time{}, err
}
case NULL:
return time.Time{}, nil
default:
panic(util.AssertErr())
}
return format.Decode(t)
}
// Text returns the value as a string.
//
// https://www.sqlite.org/c3ref/value_blob.html
func (v *Value) Text() (string, error) {
r, err := v.RawText()
return string(r), err
}
// Blob appends to buf and returns
// the value as a []byte.
//
// https://www.sqlite.org/c3ref/value_blob.html
func (v *Value) Blob(buf []byte) ([]byte, error) {
r, err := v.RawBlob()
return append(buf, r...), err
}
// RawText returns the value as a []byte.
// The []byte is owned by SQLite and may be invalidated by
// subsequent calls to [Value] methods.
//
// https://www.sqlite.org/c3ref/value_blob.html
func (v *Value) RawText() ([]byte, error) {
r := v.c.call(v.c.api.valueText, uint64(v.handle))
return v.rawBytes(uint32(r))
}
// RawBlob returns the value as a []byte.
// The []byte is owned by SQLite and may be invalidated by
// subsequent calls to [Value] methods.
//
// https://www.sqlite.org/c3ref/value_blob.html
func (v *Value) RawBlob() ([]byte, error) {
r := v.c.call(v.c.api.valueBlob, uint64(v.handle))
return v.rawBytes(uint32(r))
}
func (v *Value) rawBytes(ptr uint32) ([]byte, error) {
if ptr == 0 {
r := v.c.call(v.c.api.errcode, uint64(v.c.handle))
return nil, v.c.error(r)
}
r := v.c.call(v.c.api.valueBytes, uint64(v.handle))
return util.View(v.c.mod, ptr, r), nil
}