Batch column scans. (#52)

This commit is contained in:
Nuno Cruces
2024-01-16 15:18:14 +00:00
committed by GitHub
parent 1b2c267b2b
commit c822fa95c7
10 changed files with 111 additions and 33 deletions

View File

@@ -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
} }

View File

@@ -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 \

View File

@@ -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
View 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");

View File

@@ -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"

View File

@@ -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
View File

@@ -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
}

View File

@@ -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 \

View File

@@ -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 \