mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
CSV type affinity (#102)
Use sqlite-createtable-parser compiled to Wasm to parse the CREATE TABLE statement.
This commit is contained in:
8
util/vtabutil/README.md
Normal file
8
util/vtabutil/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Virtual Table utility functions
|
||||
|
||||
This package implements utilities mostly useful to virtual table implementations.
|
||||
|
||||
It also wraps a [parser](https://github.com/marcobambini/sqlite-createtable-parser)
|
||||
for the [`CREATE`](https://sqlite.org/lang_createtable.html) and
|
||||
[`ALTER TABLE`](https://sqlite.org/lang_altertable.html) commands,
|
||||
created by [Marco Bambini](https://github.com/marcobambini).
|
||||
@@ -1,4 +1,3 @@
|
||||
// Package ioutil implements virtual table utility functions.
|
||||
package vtabutil
|
||||
|
||||
import "strings"
|
||||
|
||||
145
util/vtabutil/parse.go
Normal file
145
util/vtabutil/parse.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package vtabutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
_ "embed"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
const (
|
||||
code = 4
|
||||
base = 8
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed parse/sql3parse_table.wasm
|
||||
binary []byte
|
||||
ctx context.Context
|
||||
once sync.Once
|
||||
runtime wazero.Runtime
|
||||
)
|
||||
|
||||
// Table holds metadata about a table.
|
||||
type Table struct {
|
||||
mod api.Module
|
||||
ptr uint32
|
||||
sql string
|
||||
}
|
||||
|
||||
// Parse parses a [CREATE] or [ALTER TABLE] command.
|
||||
//
|
||||
// [CREATE]: https://sqlite.org/lang_createtable.html
|
||||
// [ALTER TABLE]: https://sqlite.org/lang_altertable.html
|
||||
func Parse(sql string) (*Table, error) {
|
||||
once.Do(func() {
|
||||
ctx = context.Background()
|
||||
cfg := wazero.NewRuntimeConfigInterpreter().WithDebugInfoEnabled(false)
|
||||
runtime = wazero.NewRuntimeWithConfig(ctx, cfg)
|
||||
})
|
||||
|
||||
mod, err := runtime.InstantiateWithConfig(ctx, binary, wazero.NewModuleConfig().WithName(""))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if buf, ok := mod.Memory().Read(base, uint32(len(sql))); ok {
|
||||
copy(buf, sql)
|
||||
}
|
||||
r, err := mod.ExportedFunction("sql3parse_table").Call(ctx, base, uint64(len(sql)), code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, _ := mod.Memory().ReadUint32Le(code)
|
||||
if c == uint32(_MEMORY) {
|
||||
panic(util.OOMErr)
|
||||
}
|
||||
if c != uint32(_NONE) {
|
||||
return nil, ecode(c)
|
||||
}
|
||||
if r[0] == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return &Table{
|
||||
sql: sql,
|
||||
mod: mod,
|
||||
ptr: uint32(r[0]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close closes a table handle.
|
||||
func (t *Table) Close() error {
|
||||
mod := t.mod
|
||||
t.mod = nil
|
||||
return mod.Close(ctx)
|
||||
}
|
||||
|
||||
// NumColumns returns the number of columns of the table.
|
||||
func (t *Table) NumColumns() int {
|
||||
r, err := t.mod.ExportedFunction("sql3table_num_columns").Call(ctx, uint64(t.ptr))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return int(int32(r[0]))
|
||||
}
|
||||
|
||||
// Column returns data for the ith column of the table.
|
||||
//
|
||||
// https://sqlite.org/lang_createtable.html#column_definitions
|
||||
func (t *Table) Column(i int) Column {
|
||||
r, err := t.mod.ExportedFunction("sql3table_get_column").Call(ctx, uint64(t.ptr), uint64(i))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return Column{
|
||||
tab: t,
|
||||
ptr: uint32(r[0]),
|
||||
}
|
||||
}
|
||||
|
||||
// Column holds metadata about a column.
|
||||
type Column struct {
|
||||
tab *Table
|
||||
ptr uint32
|
||||
}
|
||||
|
||||
// Type returns the declared type of a column.
|
||||
//
|
||||
// https://sqlite.org/lang_createtable.html#column_data_types
|
||||
func (c Column) Type() string {
|
||||
r, err := c.tab.mod.ExportedFunction("sql3column_type").Call(ctx, uint64(c.ptr))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if r[0] == 0 {
|
||||
return ""
|
||||
}
|
||||
off, _ := c.tab.mod.Memory().ReadUint32Le(uint32(r[0]) + 0)
|
||||
len, _ := c.tab.mod.Memory().ReadUint32Le(uint32(r[0]) + 4)
|
||||
return c.tab.sql[off-base : off+len-base]
|
||||
}
|
||||
|
||||
type ecode uint32
|
||||
|
||||
const (
|
||||
_NONE ecode = iota
|
||||
_MEMORY
|
||||
_SYNTAX
|
||||
_UNSUPPORTEDSQL
|
||||
)
|
||||
|
||||
func (e ecode) Error() string {
|
||||
switch e {
|
||||
case _SYNTAX:
|
||||
return "sql3parse: invalid syntax"
|
||||
case _UNSUPPORTEDSQL:
|
||||
return "sql3parse: unsupported SQL"
|
||||
default:
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
}
|
||||
2
util/vtabutil/parse/.gitignore
vendored
Normal file
2
util/vtabutil/parse/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
sql3parse_table.c
|
||||
sql3parse_table.h
|
||||
28
util/vtabutil/parse/build.sh
Executable file
28
util/vtabutil/parse/build.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd -P -- "$(dirname -- "$0")"
|
||||
|
||||
ROOT=../../../
|
||||
BINARYEN="$ROOT/tools/binaryen-version_117/bin"
|
||||
WASI_SDK="$ROOT/tools/wasi-sdk-22.0/bin"
|
||||
|
||||
"$WASI_SDK/clang" --target=wasm32-wasi -std=c17 -flto -g0 -Oz \
|
||||
-Wall -Wextra -Wno-unused-parameter -Wno-unused-function \
|
||||
-o sql3parse_table.wasm sql3parse_table.c \
|
||||
-mexec-model=reactor \
|
||||
-msimd128 -mmutable-globals -mmultivalue \
|
||||
-mbulk-memory -mreference-types \
|
||||
-mnontrapping-fptoint -msign-ext \
|
||||
-fno-stack-protector -fno-stack-clash-protection \
|
||||
-Wl,--stack-first \
|
||||
-Wl,--import-undefined \
|
||||
$(awk '{print "-Wl,--export="$0}' exports.txt)
|
||||
|
||||
trap 'rm -f sql3parse_table.tmp' EXIT
|
||||
"$BINARYEN/wasm-ctor-eval" -g -c _initialize sql3parse_table.wasm -o sql3parse_table.tmp
|
||||
"$BINARYEN/wasm-opt" -g --strip --strip-producers -c -Oz \
|
||||
sql3parse_table.tmp -o sql3parse_table.wasm \
|
||||
--enable-simd --enable-mutable-globals --enable-multivalue \
|
||||
--enable-bulk-memory --enable-reference-types \
|
||||
--enable-nontrapping-float-to-int --enable-sign-ext
|
||||
7
util/vtabutil/parse/download.sh
Executable file
7
util/vtabutil/parse/download.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd -P -- "$(dirname -- "$0")"
|
||||
|
||||
curl -#OL "https://github.com/ncruces/sqlite-createtable-parser/raw/master/sql3parse_table.c"
|
||||
curl -#OL "https://github.com/ncruces/sqlite-createtable-parser/raw/master/sql3parse_table.h"
|
||||
4
util/vtabutil/parse/exports.txt
Normal file
4
util/vtabutil/parse/exports.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
sql3parse_table
|
||||
sql3table_get_column
|
||||
sql3table_num_columns
|
||||
sql3column_type
|
||||
BIN
util/vtabutil/parse/sql3parse_table.wasm
Executable file
BIN
util/vtabutil/parse/sql3parse_table.wasm
Executable file
Binary file not shown.
2
util/vtabutil/vtabutil.go
Normal file
2
util/vtabutil/vtabutil.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package vtabutil implements virtual table utility functions.
|
||||
package vtabutil
|
||||
Reference in New Issue
Block a user