mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
Batch column scans. (#52)
This commit is contained in:
@@ -50,6 +50,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/ncruces/go-sqlite3"
|
"github.com/ncruces/go-sqlite3"
|
||||||
"github.com/ncruces/go-sqlite3/internal/util"
|
"github.com/ncruces/go-sqlite3/internal/util"
|
||||||
@@ -532,46 +533,34 @@ func (r *rows) Next(dest []driver.Value) error {
|
|||||||
return io.EOF
|
return io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data := unsafe.Slice((*any)(unsafe.SliceData(dest)), len(dest))
|
||||||
|
err := r.Stmt.Columns(data)
|
||||||
for i := range dest {
|
for i := range dest {
|
||||||
t := r.Stmt.ColumnType(i)
|
if t, ok := r.decodeTime(i, dest[i]); ok {
|
||||||
if tm, ok := r.decodeTime(i, t); ok {
|
dest[i] = t
|
||||||
dest[i] = tm
|
} else if s, ok := dest[i].(string); ok {
|
||||||
continue
|
dest[i] = stringOrTime(s)
|
||||||
}
|
|
||||||
switch t {
|
|
||||||
case sqlite3.INTEGER:
|
|
||||||
dest[i] = r.Stmt.ColumnInt64(i)
|
|
||||||
case sqlite3.FLOAT:
|
|
||||||
dest[i] = r.Stmt.ColumnFloat(i)
|
|
||||||
case sqlite3.BLOB:
|
|
||||||
dest[i] = r.Stmt.ColumnRawBlob(i)
|
|
||||||
case sqlite3.TEXT:
|
|
||||||
dest[i] = stringOrTime(r.Stmt.ColumnText(i))
|
|
||||||
case sqlite3.NULL:
|
|
||||||
dest[i] = nil
|
|
||||||
default:
|
|
||||||
panic(util.AssertErr())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
return r.Stmt.Err()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *rows) decodeTime(i int, typ sqlite3.Datatype) (_ time.Time, _ bool) {
|
func (r *rows) decodeTime(i int, v any) (_ time.Time, _ bool) {
|
||||||
if r.tmRead == sqlite3.TimeFormatDefault {
|
if r.tmRead == sqlite3.TimeFormatDefault {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch typ {
|
|
||||||
case sqlite3.INTEGER, sqlite3.FLOAT, sqlite3.TEXT:
|
|
||||||
// maybe
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch r.declType(i) {
|
switch r.declType(i) {
|
||||||
case "DATE", "TIME", "DATETIME", "TIMESTAMP":
|
case "DATE", "TIME", "DATETIME", "TIMESTAMP":
|
||||||
// maybe
|
// maybe
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return r.Stmt.ColumnTime(i, r.tmRead), r.Stmt.Err() == nil
|
switch v.(type) {
|
||||||
|
case int64, float64, string:
|
||||||
|
// maybe
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t, err := r.tmRead.Decode(v)
|
||||||
|
return t, err == nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ ROOT=../
|
|||||||
BINARYEN="$ROOT/tools/binaryen-version_116/bin"
|
BINARYEN="$ROOT/tools/binaryen-version_116/bin"
|
||||||
WASI_SDK="$ROOT/tools/wasi-sdk-21.0/bin"
|
WASI_SDK="$ROOT/tools/wasi-sdk-21.0/bin"
|
||||||
|
|
||||||
"$WASI_SDK/clang" --target=wasm32-wasi -flto -g0 -O2 \
|
"$WASI_SDK/clang" --target=wasm32-wasi -std=c17 -flto -g0 -O2 \
|
||||||
|
-Wall -Wextra -Wno-unused-parameter \
|
||||||
-o sqlite3.wasm "$ROOT/sqlite3/main.c" \
|
-o sqlite3.wasm "$ROOT/sqlite3/main.c" \
|
||||||
-I"$ROOT/sqlite3" \
|
-I"$ROOT/sqlite3" \
|
||||||
-mexec-model=reactor \
|
-mexec-model=reactor \
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ sqlite3_column_name
|
|||||||
sqlite3_column_text
|
sqlite3_column_text
|
||||||
sqlite3_column_type
|
sqlite3_column_type
|
||||||
sqlite3_column_value
|
sqlite3_column_value
|
||||||
|
sqlite3_columns_go
|
||||||
sqlite3_config_log_go
|
sqlite3_config_log_go
|
||||||
sqlite3_create_aggregate_function_go
|
sqlite3_create_aggregate_function_go
|
||||||
sqlite3_create_collation_go
|
sqlite3_create_collation_go
|
||||||
|
|||||||
Binary file not shown.
51
sqlite3/column.c
Normal file
51
sqlite3/column.c
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "sqlite3.h"
|
||||||
|
|
||||||
|
union sqlite3_data {
|
||||||
|
sqlite3_int64 i;
|
||||||
|
double d;
|
||||||
|
struct {
|
||||||
|
const void *ptr;
|
||||||
|
int len;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
int sqlite3_columns_go(sqlite3_stmt *stmt, int nCol, char *aType,
|
||||||
|
union sqlite3_data *aData) {
|
||||||
|
if (nCol != sqlite3_column_count(stmt)) {
|
||||||
|
return SQLITE_MISUSE;
|
||||||
|
}
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
for (int i = 0; i < nCol; ++i) {
|
||||||
|
const void *ptr = NULL;
|
||||||
|
switch (aType[i] = sqlite3_column_type(stmt, i)) {
|
||||||
|
default: // SQLITE_NULL
|
||||||
|
aData[i] = (union sqlite3_data){};
|
||||||
|
case SQLITE_INTEGER:
|
||||||
|
aData[i].i = sqlite3_column_int64(stmt, i);
|
||||||
|
continue;
|
||||||
|
case SQLITE_FLOAT:
|
||||||
|
aData[i].d = sqlite3_column_double(stmt, i);
|
||||||
|
continue;
|
||||||
|
case SQLITE_TEXT:
|
||||||
|
ptr = sqlite3_column_text(stmt, i);
|
||||||
|
break;
|
||||||
|
case SQLITE_BLOB:
|
||||||
|
ptr = sqlite3_column_blob(stmt, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ptr == NULL && rc == SQLITE_OK) {
|
||||||
|
rc = sqlite3_errcode(sqlite3_db_handle(stmt));
|
||||||
|
}
|
||||||
|
aData[i].ptr = ptr;
|
||||||
|
aData[i].len = sqlite3_column_bytes(stmt, i);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(offsetof(union sqlite3_data, i) == 0, "Unexpected offset");
|
||||||
|
static_assert(offsetof(union sqlite3_data, d) == 0, "Unexpected offset");
|
||||||
|
static_assert(offsetof(union sqlite3_data, ptr) == 0, "Unexpected offset");
|
||||||
|
static_assert(offsetof(union sqlite3_data, len) == 4, "Unexpected offset");
|
||||||
|
static_assert(sizeof(union sqlite3_data) == 8, "Unexpected size");
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "ext/uint.c"
|
#include "ext/uint.c"
|
||||||
#include "ext/uuid.c"
|
#include "ext/uuid.c"
|
||||||
// Bindings
|
// Bindings
|
||||||
|
#include "column.c"
|
||||||
#include "func.c"
|
#include "func.c"
|
||||||
#include "log.c"
|
#include "log.c"
|
||||||
#include "pointer.c"
|
#include "pointer.c"
|
||||||
|
|||||||
@@ -136,8 +136,6 @@ static int go_cur_close_wrapper(sqlite3_vtab_cursor *pCursor) {
|
|||||||
static int go_vtab_find_function_wrapper(
|
static int go_vtab_find_function_wrapper(
|
||||||
sqlite3_vtab *pVTab, int nArg, const char *zName,
|
sqlite3_vtab *pVTab, int nArg, const char *zName,
|
||||||
void (**pxFunc)(sqlite3_context *, int, sqlite3_value **), void **ppArg) {
|
void (**pxFunc)(sqlite3_context *, int, sqlite3_value **), void **ppArg) {
|
||||||
struct go_vtab *vtab = container_of(pVTab, struct go_vtab, base);
|
|
||||||
|
|
||||||
go_handle handle;
|
go_handle handle;
|
||||||
int rc = go_vtab_find_function(pVTab, nArg, zName, &handle);
|
int rc = go_vtab_find_function(pVTab, nArg, zName, &handle);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
|||||||
37
stmt.go
37
stmt.go
@@ -549,3 +549,40 @@ func (s *Stmt) ColumnValue(col int) Value {
|
|||||||
handle: uint32(r),
|
handle: uint32(r),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Stmt) Columns(dest []any) error {
|
||||||
|
defer s.c.arena.mark()()
|
||||||
|
count := uint64(len(dest))
|
||||||
|
typePtr := s.c.arena.new(count)
|
||||||
|
dataPtr := s.c.arena.new(8 * count)
|
||||||
|
|
||||||
|
r := s.c.call("sqlite3_columns_go",
|
||||||
|
uint64(s.handle), count, uint64(typePtr), uint64(dataPtr))
|
||||||
|
if err := s.c.error(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
types := util.View(s.c.mod, typePtr, count)
|
||||||
|
for i := range dest {
|
||||||
|
switch types[i] {
|
||||||
|
case byte(INTEGER):
|
||||||
|
dest[i] = int64(util.ReadUint64(s.c.mod, dataPtr+8*uint32(i)))
|
||||||
|
continue
|
||||||
|
case byte(FLOAT):
|
||||||
|
dest[i] = util.ReadFloat64(s.c.mod, dataPtr+8*uint32(i))
|
||||||
|
continue
|
||||||
|
case byte(NULL):
|
||||||
|
dest[i] = nil
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ptr := util.ReadUint32(s.c.mod, dataPtr+8*uint32(i)+0)
|
||||||
|
len := util.ReadUint32(s.c.mod, dataPtr+8*uint32(i)+4)
|
||||||
|
buf := util.View(s.c.mod, ptr, uint64(len))
|
||||||
|
if types[i] == byte(TEXT) {
|
||||||
|
dest[i] = string(buf)
|
||||||
|
} else {
|
||||||
|
dest[i] = buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
2
vfs/tests/mptest/testdata/build.sh
vendored
2
vfs/tests/mptest/testdata/build.sh
vendored
@@ -7,7 +7,7 @@ ROOT=../../../../
|
|||||||
BINARYEN="$ROOT/tools/binaryen-version_116/bin"
|
BINARYEN="$ROOT/tools/binaryen-version_116/bin"
|
||||||
WASI_SDK="$ROOT/tools/wasi-sdk-21.0/bin"
|
WASI_SDK="$ROOT/tools/wasi-sdk-21.0/bin"
|
||||||
|
|
||||||
"$WASI_SDK/clang" --target=wasm32-wasi -flto -g0 -O2 \
|
"$WASI_SDK/clang" --target=wasm32-wasi -std=c17 -flto -g0 -O2 \
|
||||||
-o mptest.wasm main.c \
|
-o mptest.wasm main.c \
|
||||||
-I"$ROOT/sqlite3" \
|
-I"$ROOT/sqlite3" \
|
||||||
-msimd128 -mmutable-globals \
|
-msimd128 -mmutable-globals \
|
||||||
|
|||||||
2
vfs/tests/speedtest1/testdata/build.sh
vendored
2
vfs/tests/speedtest1/testdata/build.sh
vendored
@@ -7,7 +7,7 @@ ROOT=../../../../
|
|||||||
BINARYEN="$ROOT/tools/binaryen-version_116/bin"
|
BINARYEN="$ROOT/tools/binaryen-version_116/bin"
|
||||||
WASI_SDK="$ROOT/tools/wasi-sdk-21.0/bin"
|
WASI_SDK="$ROOT/tools/wasi-sdk-21.0/bin"
|
||||||
|
|
||||||
"$WASI_SDK/clang" --target=wasm32-wasi -flto -g0 -O2 \
|
"$WASI_SDK/clang" --target=wasm32-wasi -std=c17 -flto -g0 -O2 \
|
||||||
-o speedtest1.wasm main.c \
|
-o speedtest1.wasm main.c \
|
||||||
-I"$ROOT/sqlite3" \
|
-I"$ROOT/sqlite3" \
|
||||||
-msimd128 -mmutable-globals \
|
-msimd128 -mmutable-globals \
|
||||||
|
|||||||
Reference in New Issue
Block a user