Unprotected values.

This commit is contained in:
Nuno Cruces
2023-11-29 16:09:30 +00:00
parent 3f05115cd7
commit dbaf2d99cd
6 changed files with 51 additions and 10 deletions

View File

@@ -26,6 +26,7 @@ sqlite3_bind_text64
sqlite3_bind_blob64 sqlite3_bind_blob64
sqlite3_bind_zeroblob64 sqlite3_bind_zeroblob64
sqlite3_bind_pointer_go sqlite3_bind_pointer_go
sqlite3_bind_value
sqlite3_column_count sqlite3_column_count
sqlite3_column_name sqlite3_column_name
sqlite3_column_type sqlite3_column_type
@@ -34,6 +35,7 @@ sqlite3_column_double
sqlite3_column_text sqlite3_column_text
sqlite3_column_blob sqlite3_column_blob
sqlite3_column_bytes sqlite3_column_bytes
sqlite3_column_value
sqlite3_blob_open sqlite3_blob_open
sqlite3_blob_close sqlite3_blob_close
sqlite3_blob_reopen sqlite3_blob_reopen

Binary file not shown.

View File

@@ -133,6 +133,7 @@ func instantiateSQLite() (sqlt *sqlite, err error) {
bindBlob: getFun("sqlite3_bind_blob64"), bindBlob: getFun("sqlite3_bind_blob64"),
bindZeroBlob: getFun("sqlite3_bind_zeroblob64"), bindZeroBlob: getFun("sqlite3_bind_zeroblob64"),
bindPointer: getFun("sqlite3_bind_pointer_go"), bindPointer: getFun("sqlite3_bind_pointer_go"),
bindValue: getFun("sqlite3_bind_value"),
columnCount: getFun("sqlite3_column_count"), columnCount: getFun("sqlite3_column_count"),
columnName: getFun("sqlite3_column_name"), columnName: getFun("sqlite3_column_name"),
columnType: getFun("sqlite3_column_type"), columnType: getFun("sqlite3_column_type"),
@@ -141,6 +142,7 @@ func instantiateSQLite() (sqlt *sqlite, err error) {
columnText: getFun("sqlite3_column_text"), columnText: getFun("sqlite3_column_text"),
columnBlob: getFun("sqlite3_column_blob"), columnBlob: getFun("sqlite3_column_blob"),
columnBytes: getFun("sqlite3_column_bytes"), columnBytes: getFun("sqlite3_column_bytes"),
columnValue: getFun("sqlite3_column_value"),
blobOpen: getFun("sqlite3_blob_open"), blobOpen: getFun("sqlite3_blob_open"),
blobClose: getFun("sqlite3_blob_close"), blobClose: getFun("sqlite3_blob_close"),
blobReopen: getFun("sqlite3_blob_reopen"), blobReopen: getFun("sqlite3_blob_reopen"),
@@ -367,6 +369,7 @@ type sqliteAPI struct {
bindBlob api.Function bindBlob api.Function
bindZeroBlob api.Function bindZeroBlob api.Function
bindPointer api.Function bindPointer api.Function
bindValue api.Function
columnCount api.Function columnCount api.Function
columnName api.Function columnName api.Function
columnType api.Function columnType api.Function
@@ -375,6 +378,7 @@ type sqliteAPI struct {
columnText api.Function columnText api.Function
columnBlob api.Function columnBlob api.Function
columnBytes api.Function columnBytes api.Function
columnValue api.Function
blobOpen api.Function blobOpen api.Function
blobClose api.Function blobClose api.Function
blobReopen api.Function blobReopen api.Function

27
stmt.go
View File

@@ -297,6 +297,19 @@ func (s *Stmt) BindJSON(param int, value any) error {
return s.BindRawText(param, data) return s.BindRawText(param, data)
} }
// BindValue binds a copy of value to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindValue(param int, value Value) error {
if value.sqlite != s.c.sqlite {
return MISUSE
}
r := s.c.call(s.c.api.bindValue,
uint64(s.handle), uint64(param), uint64(value.handle))
return s.c.error(r)
}
// ColumnCount returns the number of columns in a result set. // ColumnCount returns the number of columns in a result set.
// //
// https://sqlite.org/c3ref/column_count.html // https://sqlite.org/c3ref/column_count.html
@@ -475,6 +488,20 @@ func (s *Stmt) ColumnJSON(col int, ptr any) error {
return json.Unmarshal(data, ptr) return json.Unmarshal(data, ptr)
} }
// ColumnValue returns the unprotected value of the result column.
// The leftmost column of the result set has the index 0.
//
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnValue(col int) Value {
r := s.c.call(s.c.api.columnValue,
uint64(s.handle), uint64(col))
return Value{
unprot: true,
sqlite: s.c.sqlite,
handle: uint32(r),
}
}
// Return true if stmt is an empty SQL statement. // Return true if stmt is an empty SQL statement.
// This is used as an optimization. // This is used as an optimization.
// It's OK to always return false here. // It's OK to always return false here.

View File

@@ -15,13 +15,21 @@ import (
type Value struct { type Value struct {
*sqlite *sqlite
handle uint32 handle uint32
unprot bool
}
func (v Value) protected() uint64 {
if v.unprot {
panic(util.ValueErr)
}
return uint64(v.handle)
} }
// Type returns the initial [Datatype] of the value. // Type returns the initial [Datatype] of the value.
// //
// https://sqlite.org/c3ref/value_blob.html // https://sqlite.org/c3ref/value_blob.html
func (v Value) Type() Datatype { func (v Value) Type() Datatype {
r := v.call(v.api.valueType, uint64(v.handle)) r := v.call(v.api.valueType, v.protected())
return Datatype(r) return Datatype(r)
} }
@@ -49,7 +57,7 @@ func (v Value) Int() int {
// //
// https://sqlite.org/c3ref/value_blob.html // https://sqlite.org/c3ref/value_blob.html
func (v Value) Int64() int64 { func (v Value) Int64() int64 {
r := v.call(v.api.valueInteger, uint64(v.handle)) r := v.call(v.api.valueInteger, v.protected())
return int64(r) return int64(r)
} }
@@ -57,7 +65,7 @@ func (v Value) Int64() int64 {
// //
// https://sqlite.org/c3ref/value_blob.html // https://sqlite.org/c3ref/value_blob.html
func (v Value) Float() float64 { func (v Value) Float() float64 {
r := v.call(v.api.valueFloat, uint64(v.handle)) r := v.call(v.api.valueFloat, v.protected())
return math.Float64frombits(r) return math.Float64frombits(r)
} }
@@ -103,7 +111,7 @@ func (v Value) Blob(buf []byte) []byte {
// //
// https://sqlite.org/c3ref/value_blob.html // https://sqlite.org/c3ref/value_blob.html
func (v Value) RawText() []byte { func (v Value) RawText() []byte {
r := v.call(v.api.valueText, uint64(v.handle)) r := v.call(v.api.valueText, v.protected())
return v.rawBytes(uint32(r)) return v.rawBytes(uint32(r))
} }
@@ -113,7 +121,7 @@ func (v Value) RawText() []byte {
// //
// https://sqlite.org/c3ref/value_blob.html // https://sqlite.org/c3ref/value_blob.html
func (v Value) RawBlob() []byte { func (v Value) RawBlob() []byte {
r := v.call(v.api.valueBlob, uint64(v.handle)) r := v.call(v.api.valueBlob, v.protected())
return v.rawBytes(uint32(r)) return v.rawBytes(uint32(r))
} }
@@ -122,14 +130,14 @@ func (v Value) rawBytes(ptr uint32) []byte {
return nil return nil
} }
r := v.call(v.api.valueBytes, uint64(v.handle)) r := v.call(v.api.valueBytes, v.protected())
return util.View(v.mod, ptr, r) return util.View(v.mod, ptr, r)
} }
// Pointer gets the pointer associated with this value, // Pointer gets the pointer associated with this value,
// or nil if it has no associated pointer. // or nil if it has no associated pointer.
func (v Value) Pointer() any { func (v Value) Pointer() any {
r := v.call(v.api.valuePointer, uint64(v.handle)) r := v.call(v.api.valuePointer, v.protected())
return util.GetHandle(v.ctx, uint32(r)) return util.GetHandle(v.ctx, uint32(r))
} }

View File

@@ -254,15 +254,15 @@ type IndexConstraintUsage struct {
// if the right-hand operand is known. // if the right-hand operand is known.
// //
// https://sqlite.org/c3ref/vtab_rhs_value.html // https://sqlite.org/c3ref/vtab_rhs_value.html
func (idx *IndexInfo) RHSValue(column int) (*Value, error) { func (idx *IndexInfo) RHSValue(column int) (Value, error) {
defer idx.c.arena.mark()() defer idx.c.arena.mark()()
valPtr := idx.c.arena.new(ptrlen) valPtr := idx.c.arena.new(ptrlen)
r := idx.c.call(idx.c.api.vtabRHSValue, r := idx.c.call(idx.c.api.vtabRHSValue,
uint64(idx.handle), uint64(column), uint64(valPtr)) uint64(idx.handle), uint64(column), uint64(valPtr))
if err := idx.c.error(r); err != nil { if err := idx.c.error(r); err != nil {
return nil, err return Value{}, err
} }
return &Value{ return Value{
sqlite: idx.c.sqlite, sqlite: idx.c.sqlite,
handle: util.ReadUint32(idx.c.mod, valPtr), handle: util.ReadUint32(idx.c.mod, valPtr),
}, nil }, nil