mirror of
https://github.com/fluencelabs/sqlite
synced 2025-04-24 17:02:14 +00:00
make compatible with sqlite-wasm-connector
This commit is contained in:
parent
f9a8e85da4
commit
43bd1080a2
@ -2,5 +2,5 @@ modules_dir = "./"
|
|||||||
|
|
||||||
[[module]]
|
[[module]]
|
||||||
name = "sqlite3"
|
name = "sqlite3"
|
||||||
mem_pages_count = 100
|
mem_pages_count = 1000
|
||||||
logger_enabled = true
|
logger_enabled = true
|
||||||
|
@ -6,7 +6,7 @@ RUN apt-get update \
|
|||||||
git \
|
git \
|
||||||
make
|
make
|
||||||
|
|
||||||
RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-10/wasi-sdk-10.0-linux.tar.gz | tar xz --strip-components=1 -C /
|
RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-11/wasi-sdk-11.0-linux.tar.gz | tar xz --strip-components=1 -C /
|
||||||
|
|
||||||
VOLUME /code
|
VOLUME /code
|
||||||
WORKDIR /code
|
WORKDIR /code
|
||||||
|
28
Makefile
28
Makefile
@ -3,6 +3,7 @@ CC = /bin/clang
|
|||||||
SYSROOT = /share/wasi-sysroot
|
SYSROOT = /share/wasi-sysroot
|
||||||
TARGET_TRIPLE = wasm32-wasi
|
TARGET_TRIPLE = wasm32-wasi
|
||||||
CFLAGS = -nostartfiles -fvisibility=hidden
|
CFLAGS = -nostartfiles -fvisibility=hidden
|
||||||
|
SDK = sdk/logger.h
|
||||||
LDFLAGS = -Wl,--no-entry,--demangle,--allow-undefined
|
LDFLAGS = -Wl,--no-entry,--demangle,--allow-undefined
|
||||||
EXPORT_FUNCS = \
|
EXPORT_FUNCS = \
|
||||||
--export=allocate,$\
|
--export=allocate,$\
|
||||||
@ -11,7 +12,32 @@ EXPORT_FUNCS = \
|
|||||||
--export=set_result_ptr,$\
|
--export=set_result_ptr,$\
|
||||||
--export=get_result_size,$\
|
--export=get_result_size,$\
|
||||||
--export=get_result_ptr,$\
|
--export=get_result_ptr,$\
|
||||||
--export=invoke
|
--export=sqlite3_open_v2_,$\
|
||||||
|
--export=sqlite3_close,$\
|
||||||
|
--export=sqlite3_prepare_v2_,$\
|
||||||
|
--export=sqlite3_exec_,$\
|
||||||
|
--export=sqlite3_libversion_number,$\
|
||||||
|
--export=sqlite3_total_changes,$\
|
||||||
|
--export=sqlite3_changes,$\
|
||||||
|
--export=sqlite3_busy_timeout,$\
|
||||||
|
--export=sqlite3_errmsg_,$\
|
||||||
|
--export=sqlite3_errcode,$\
|
||||||
|
--export=sqlite3_column_type,$\
|
||||||
|
--export=sqlite3_column_name_,$\
|
||||||
|
--export=sqlite3_step,$\
|
||||||
|
--export=sqlite3_reset,$\
|
||||||
|
--export=sqlite3_bind_blob_,$\
|
||||||
|
--export=sqlite3_bind_double,$\
|
||||||
|
--export=sqlite3_bind_int64,$\
|
||||||
|
--export=sqlite3_bind_text_,$\
|
||||||
|
--export=sqlite3_bind_null,$\
|
||||||
|
--export=sqlite3_column_count,$\
|
||||||
|
--export=sqlite3_column_double,$\
|
||||||
|
--export=sqlite3_column_int64,$\
|
||||||
|
--export=sqlite3_column_text_,$\
|
||||||
|
--export=sqlite3_column_blob_,$\
|
||||||
|
--export=sqlite3_column_bytes,$\
|
||||||
|
--export=sqlite3_finalize
|
||||||
SQLITE_SRC = \
|
SQLITE_SRC = \
|
||||||
src/alter.c\
|
src/alter.c\
|
||||||
src/analyze.c\
|
src/analyze.c\
|
||||||
|
493
sqlite3.wit
493
sqlite3.wit
@ -1,43 +1,466 @@
|
|||||||
;; Fluence SQLite fork Wasm Interface Types
|
;; Fluence SQLite fork Wasm Interface Types
|
||||||
|
|
||||||
;; allocate
|
;; Types
|
||||||
(@interface type (func (param $size: i32) (result i32))) ;; 0
|
(@interface type (func
|
||||||
|
(param $size: i32)
|
||||||
|
(result i32))) ;; 0
|
||||||
|
(@interface type (func
|
||||||
|
(param $pointer: i32 $size: i32) )) ;; 1
|
||||||
|
(@interface type (func
|
||||||
|
(result i32))) ;; 2
|
||||||
|
(@interface type (func
|
||||||
|
(result i32))) ;; 3
|
||||||
|
(@interface type (func
|
||||||
|
(param $result_size: i32) )) ;; 4
|
||||||
|
(@interface type (func
|
||||||
|
(param $result_ptr: i32) )) ;; 5
|
||||||
|
(@interface type (record $DBExecDescriptor (
|
||||||
|
field $ret_code: s32
|
||||||
|
field $err_msg: string
|
||||||
|
))) ;; 6
|
||||||
|
(@interface type (record $DBPrepareDescriptor (
|
||||||
|
field $ret_code: s32
|
||||||
|
field $stmt_handle: u32
|
||||||
|
field $tail: u32
|
||||||
|
))) ;; 7
|
||||||
|
(@interface type (record $DBOpenDescriptor (
|
||||||
|
field $ret_code: s32
|
||||||
|
field $db_handle: u32
|
||||||
|
))) ;; 8
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $icol: u32)
|
||||||
|
(result string))) ;; 9
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $icol: u32)
|
||||||
|
(result string))) ;; 10
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $icol: u32)
|
||||||
|
(result s32))) ;; 11
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $icol: u32)
|
||||||
|
(result s32))) ;; 12
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32)
|
||||||
|
(result s32))) ;; 13
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32)
|
||||||
|
(result s32))) ;; 14
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $pos: s32 $value: f64)
|
||||||
|
(result s32))) ;; 15
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $pos: s32 $value: f64)
|
||||||
|
(result s32))) ;; 16
|
||||||
|
(@interface type (func
|
||||||
|
(param $filename: string $flags: s32 $vfs: string)
|
||||||
|
)) ;; 17
|
||||||
|
(@interface type (func
|
||||||
|
(param $filename: string $flags: s32 $vfs: string)
|
||||||
|
)) ;; 18
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32)
|
||||||
|
(result s32))) ;; 19
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32)
|
||||||
|
(result s32))) ;; 20
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32)
|
||||||
|
(result s32))) ;; 21
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32)
|
||||||
|
(result s32))) ;; 22
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $icol: u32)
|
||||||
|
(result s64))) ;; 23
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $icol: u32)
|
||||||
|
(result s64))) ;; 24
|
||||||
|
(@interface type (func
|
||||||
|
(param $db: u32)
|
||||||
|
(result s32))) ;; 25
|
||||||
|
(@interface type (func
|
||||||
|
(param $db: u32)
|
||||||
|
(result s32))) ;; 26
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $icol: s32)
|
||||||
|
(result f64))) ;; 27
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $icol: s32)
|
||||||
|
(result f64))) ;; 28
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32 $ms: u32)
|
||||||
|
(result s32))) ;; 29
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32 $ms: u32)
|
||||||
|
(result s32))) ;; 30
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32)
|
||||||
|
(result string))) ;; 31
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32)
|
||||||
|
(result string))) ;; 32
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $pos: s32 $value: s64)
|
||||||
|
(result s32))) ;; 33
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $pos: s32 $value: s64)
|
||||||
|
(result s32))) ;; 34
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32)
|
||||||
|
(result s32))) ;; 35
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32)
|
||||||
|
(result s32))) ;; 36
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32 $sql: string)
|
||||||
|
)) ;; 37
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32 $sql: string)
|
||||||
|
)) ;; 38
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $pos: s32)
|
||||||
|
(result s32))) ;; 39
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $pos: s32)
|
||||||
|
(result s32))) ;; 40
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32)
|
||||||
|
(result s32))) ;; 41
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32)
|
||||||
|
(result s32))) ;; 42
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $pos: s32 $blob: byte_array $xDel: s32)
|
||||||
|
(result s32))) ;; 43
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $pos: s32 $blob: byte_array $xDel: s32)
|
||||||
|
(result s32))) ;; 44
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32)
|
||||||
|
(result s32))) ;; 45
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32)
|
||||||
|
(result s32))) ;; 46
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $pos: s32 $text: string $xDel: s32)
|
||||||
|
(result s32))) ;; 47
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $pos: s32 $text: string $xDel: s32)
|
||||||
|
(result s32))) ;; 48
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32)
|
||||||
|
(result s32))) ;; 49
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32)
|
||||||
|
(result s32))) ;; 50
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32 $sql: string $callback_id: s32 $callback_arg: s32)
|
||||||
|
)) ;; 51
|
||||||
|
(@interface type (func
|
||||||
|
(param $db_handle: u32 $sql: string $callback_id: s32 $callback_arg: s32)
|
||||||
|
)) ;; 52
|
||||||
|
(@interface type (func
|
||||||
|
(result s32))) ;; 53
|
||||||
|
(@interface type (func
|
||||||
|
(result s32))) ;; 54
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $icol: s32)
|
||||||
|
(result byte_array))) ;; 55
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $icol: s32)
|
||||||
|
(result byte_array))) ;; 56
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $N: u32)
|
||||||
|
(result string))) ;; 57
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $N: u32)
|
||||||
|
(result string))) ;; 58
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $icol: u32)
|
||||||
|
(result s32))) ;; 59
|
||||||
|
(@interface type (func
|
||||||
|
(param $stmt_handle: u32 $icol: u32)
|
||||||
|
(result s32))) ;; 60
|
||||||
|
|
||||||
;; deallocate
|
|
||||||
(@interface type (func (param $pointer: i32 $size: i32))) ;; 1
|
|
||||||
|
|
||||||
;; invoke
|
|
||||||
(@interface type (func (param $request: string) (result string))) ;; 2
|
|
||||||
|
|
||||||
;; get_result_ptr/get_result_size
|
;; Adapters
|
||||||
(@interface type (func (result i32))) ;; 3
|
(@interface func (type 9)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
i32.from_u32
|
||||||
|
call-core 6
|
||||||
|
call-core 3
|
||||||
|
call-core 2
|
||||||
|
string.lift_memory
|
||||||
|
call-core 3
|
||||||
|
call-core 2
|
||||||
|
call-core 1)
|
||||||
|
(@interface func (type 11)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
i32.from_u32
|
||||||
|
call-core 7
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 13)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
call-core 8
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 15)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
i32.from_s32
|
||||||
|
arg.get 2
|
||||||
|
call-core 9
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 17)
|
||||||
|
arg.get 0
|
||||||
|
string.size
|
||||||
|
call-core 0
|
||||||
|
arg.get 0
|
||||||
|
string.lower_memory
|
||||||
|
arg.get 1
|
||||||
|
i32.from_s32
|
||||||
|
arg.get 2
|
||||||
|
string.size
|
||||||
|
call-core 0
|
||||||
|
arg.get 2
|
||||||
|
string.lower_memory
|
||||||
|
call-core 10
|
||||||
|
call-core 3
|
||||||
|
record.lift_memory 8)
|
||||||
|
(@interface func (type 19)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
call-core 11
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 21)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
call-core 12
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 23)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
i32.from_u32
|
||||||
|
call-core 13
|
||||||
|
s64.from_i64)
|
||||||
|
(@interface func (type 25)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
call-core 14
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 27)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
i32.from_s32
|
||||||
|
call-core 15)
|
||||||
|
(@interface func (type 29)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
i32.from_u32
|
||||||
|
call-core 16
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 31)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
call-core 17
|
||||||
|
call-core 3
|
||||||
|
call-core 2
|
||||||
|
string.lift_memory
|
||||||
|
call-core 3
|
||||||
|
call-core 2
|
||||||
|
call-core 1)
|
||||||
|
(@interface func (type 33)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
i32.from_s32
|
||||||
|
arg.get 2
|
||||||
|
i64.from_s64
|
||||||
|
call-core 18
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 35)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
call-core 19
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 37)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
string.size
|
||||||
|
call-core 0
|
||||||
|
arg.get 1
|
||||||
|
string.lower_memory
|
||||||
|
call-core 20
|
||||||
|
call-core 3
|
||||||
|
record.lift_memory 7)
|
||||||
|
(@interface func (type 39)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
i32.from_s32
|
||||||
|
call-core 21
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 41)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
call-core 22
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 43)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
i32.from_s32
|
||||||
|
arg.get 2
|
||||||
|
byte_array.size
|
||||||
|
call-core 0
|
||||||
|
arg.get 2
|
||||||
|
byte_array.lower_memory
|
||||||
|
arg.get 3
|
||||||
|
i32.from_s32
|
||||||
|
call-core 23
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 45)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
call-core 24
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 47)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
i32.from_s32
|
||||||
|
arg.get 2
|
||||||
|
string.size
|
||||||
|
call-core 0
|
||||||
|
arg.get 2
|
||||||
|
string.lower_memory
|
||||||
|
arg.get 3
|
||||||
|
i32.from_s32
|
||||||
|
call-core 25
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 49)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
call-core 26
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 51)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
string.size
|
||||||
|
call-core 0
|
||||||
|
arg.get 1
|
||||||
|
string.lower_memory
|
||||||
|
arg.get 2
|
||||||
|
i32.from_s32
|
||||||
|
arg.get 3
|
||||||
|
i32.from_s32
|
||||||
|
call-core 27
|
||||||
|
call-core 3
|
||||||
|
record.lift_memory 6)
|
||||||
|
(@interface func (type 53)
|
||||||
|
call-core 28
|
||||||
|
s32.from_i32)
|
||||||
|
(@interface func (type 55)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
i32.from_s32
|
||||||
|
call-core 29
|
||||||
|
call-core 3
|
||||||
|
call-core 2
|
||||||
|
byte_array.lift_memory
|
||||||
|
call-core 3
|
||||||
|
call-core 2
|
||||||
|
call-core 1)
|
||||||
|
(@interface func (type 57)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
i32.from_u32
|
||||||
|
call-core 30
|
||||||
|
call-core 3
|
||||||
|
call-core 2
|
||||||
|
string.lift_memory
|
||||||
|
call-core 3
|
||||||
|
call-core 2
|
||||||
|
call-core 1)
|
||||||
|
(@interface func (type 59)
|
||||||
|
arg.get 0
|
||||||
|
i32.from_u32
|
||||||
|
arg.get 1
|
||||||
|
i32.from_u32
|
||||||
|
call-core 31
|
||||||
|
s32.from_i32)
|
||||||
|
|
||||||
;; set_result_ptr/set_result_size
|
;; Exports
|
||||||
(@interface type (func (param $result: i32))) ;; 4
|
(@interface export "allocate" (func 0))
|
||||||
|
(@interface export "deallocate" (func 1))
|
||||||
(@interface export "allocate" (func 0)) ;; 0
|
(@interface export "get_result_size" (func 2))
|
||||||
(@interface export "deallocate" (func 1)) ;; 1
|
(@interface export "get_result_ptr" (func 3))
|
||||||
(@interface export "invoke" (func 2)) ;; 2
|
(@interface export "set_result_size" (func 4))
|
||||||
(@interface export "get_result_size" (func 3)) ;; 3
|
(@interface export "set_result_ptr" (func 5))
|
||||||
(@interface export "get_result_ptr" (func 3)) ;; 4
|
(@interface export "sqlite3_column_text" (func 10))
|
||||||
(@interface export "set_result_size" (func 4)) ;; 5
|
(@interface export "sqlite3_column_bytes" (func 12))
|
||||||
(@interface export "set_result_ptr" (func 4)) ;; 6
|
(@interface export "sqlite3_close" (func 14))
|
||||||
|
(@interface export "sqlite3_bind_double" (func 16))
|
||||||
;; adapter for export invoke function
|
(@interface export "sqlite3_open_v2" (func 18))
|
||||||
(@interface func (type 2)
|
(@interface export "sqlite3_changes" (func 20))
|
||||||
arg.get 0
|
(@interface export "sqlite3_step" (func 22))
|
||||||
string.size
|
(@interface export "sqlite3_column_int64" (func 24))
|
||||||
call-core 0 ;; call allocate
|
(@interface export "sqlite3_errcode" (func 26))
|
||||||
arg.get 0
|
(@interface export "sqlite3_column_double" (func 28))
|
||||||
string.lower_memory
|
(@interface export "sqlite3_busy_timeout" (func 30))
|
||||||
call-core 2 ;; call invoke
|
(@interface export "sqlite3_errmsg" (func 32))
|
||||||
call-core 4 ;; call get_result_size
|
(@interface export "sqlite3_bind_int64" (func 34))
|
||||||
call-core 3 ;; call get_result_ptr
|
(@interface export "sqlite3_finalize" (func 36))
|
||||||
string.lift_memory
|
(@interface export "sqlite3_prepare_v2" (func 38))
|
||||||
call-core 4 ;; call get_result_size
|
(@interface export "sqlite3_bind_null" (func 40))
|
||||||
call-core 3 ;; call get_result_ptr
|
(@interface export "sqlite3_column_count" (func 42))
|
||||||
call-core 1 ;; call deallocate
|
(@interface export "sqlite3_bind_blob" (func 44))
|
||||||
)
|
(@interface export "sqlite3_total_changes" (func 46))
|
||||||
|
(@interface export "sqlite3_bind_text" (func 48))
|
||||||
|
(@interface export "sqlite3_reset" (func 50))
|
||||||
|
(@interface export "sqlite3_exec" (func 52))
|
||||||
|
(@interface export "sqlite3_libversion_number" (func 54))
|
||||||
|
(@interface export "sqlite3_column_blob" (func 56))
|
||||||
|
(@interface export "sqlite3_column_name" (func 58))
|
||||||
|
(@interface export "sqlite3_column_type" (func 60))
|
||||||
|
|
||||||
;; Implementations
|
;; Implementations
|
||||||
(@interface implement (func 2) (func 2))
|
(@interface implement (func 10) (func 9))
|
||||||
|
(@interface implement (func 12) (func 11))
|
||||||
|
(@interface implement (func 14) (func 13))
|
||||||
|
(@interface implement (func 16) (func 15))
|
||||||
|
(@interface implement (func 18) (func 17))
|
||||||
|
(@interface implement (func 20) (func 19))
|
||||||
|
(@interface implement (func 22) (func 21))
|
||||||
|
(@interface implement (func 24) (func 23))
|
||||||
|
(@interface implement (func 26) (func 25))
|
||||||
|
(@interface implement (func 28) (func 27))
|
||||||
|
(@interface implement (func 30) (func 29))
|
||||||
|
(@interface implement (func 32) (func 31))
|
||||||
|
(@interface implement (func 34) (func 33))
|
||||||
|
(@interface implement (func 36) (func 35))
|
||||||
|
(@interface implement (func 38) (func 37))
|
||||||
|
(@interface implement (func 40) (func 39))
|
||||||
|
(@interface implement (func 42) (func 41))
|
||||||
|
(@interface implement (func 44) (func 43))
|
||||||
|
(@interface implement (func 46) (func 45))
|
||||||
|
(@interface implement (func 48) (func 47))
|
||||||
|
(@interface implement (func 50) (func 49))
|
||||||
|
(@interface implement (func 52) (func 51))
|
||||||
|
(@interface implement (func 54) (func 53))
|
||||||
|
(@interface implement (func 56) (func 55))
|
||||||
|
(@interface implement (func 58) (func 57))
|
||||||
|
(@interface implement (func 60) (func 59))
|
||||||
|
28
src/legacy.c
28
src/legacy.c
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Execute SQL code. Return one of the SQLITE_ success/failure
|
** Execute SQL code. Return one of the SQLITE_ success/failure
|
||||||
@ -27,6 +28,33 @@
|
|||||||
** argument to xCallback(). If xCallback=NULL then no callback
|
** argument to xCallback(). If xCallback=NULL then no callback
|
||||||
** is invoked, even for queries.
|
** is invoked, even for queries.
|
||||||
*/
|
*/
|
||||||
|
void sqlite3_exec_(
|
||||||
|
sqlite3 *db, /* The database on which the SQL executes */
|
||||||
|
char *zSql, /* The SQL to be executed */
|
||||||
|
int zSql_len,
|
||||||
|
sqlite3_callback xCallback, /* Invoke this callback routine */
|
||||||
|
void *pArg /* First argument to xCallback() */
|
||||||
|
) __EXPORT_NAME(sqlite3_exec) {
|
||||||
|
char *new_zSql = (char *) malloc(zSql_len + 1);
|
||||||
|
memcpy(new_zSql, zSql, zSql_len);
|
||||||
|
new_zSql[zSql_len] = 0;
|
||||||
|
free((void *)zSql);
|
||||||
|
|
||||||
|
char *pzErrMsg = 0;
|
||||||
|
const int ret_code = sqlite3_exec(db, new_zSql, xCallback, pArg, &pzErrMsg);
|
||||||
|
|
||||||
|
free(new_zSql);
|
||||||
|
int *result = malloc(3*8);
|
||||||
|
result[0] = ret_code;
|
||||||
|
result[1] = 0;
|
||||||
|
result[2] = (int) pzErrMsg;
|
||||||
|
result[3] = 0;
|
||||||
|
result[4] = strlen(pzErrMsg);
|
||||||
|
result[5] = 0;
|
||||||
|
|
||||||
|
set_result_ptr((char *)result);
|
||||||
|
}
|
||||||
|
|
||||||
int sqlite3_exec(
|
int sqlite3_exec(
|
||||||
sqlite3 *db, /* The database on which the SQL executes */
|
sqlite3 *db, /* The database on which the SQL executes */
|
||||||
const char *zSql, /* The SQL to be executed */
|
const char *zSql, /* The SQL to be executed */
|
||||||
|
47
src/main.c
47
src/main.c
@ -16,6 +16,9 @@
|
|||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
|
extern char *RESULT_PTR;
|
||||||
|
extern int RESULT_SIZE;
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_FTS3
|
#ifdef SQLITE_ENABLE_FTS3
|
||||||
# include "fts3.h"
|
# include "fts3.h"
|
||||||
#endif
|
#endif
|
||||||
@ -2450,6 +2453,13 @@ int sqlite3TempInMemory(const sqlite3 *db){
|
|||||||
** Return UTF-8 encoded English language explanation of the most recent
|
** Return UTF-8 encoded English language explanation of the most recent
|
||||||
** error.
|
** error.
|
||||||
*/
|
*/
|
||||||
|
void sqlite3_errmsg_(sqlite3 *db) __EXPORT_NAME(sqlite3_errmsg) {
|
||||||
|
const char *result = sqlite3_errmsg(db);
|
||||||
|
|
||||||
|
set_result_ptr((char *)result);
|
||||||
|
set_result_size(strlen(result));
|
||||||
|
}
|
||||||
|
|
||||||
const char *sqlite3_errmsg(sqlite3 *db){
|
const char *sqlite3_errmsg(sqlite3 *db){
|
||||||
const char *z;
|
const char *z;
|
||||||
if( !db ){
|
if( !db ){
|
||||||
@ -3428,15 +3438,50 @@ int sqlite3_open(
|
|||||||
return openDatabase(zFilename, ppDb,
|
return openDatabase(zFilename, ppDb,
|
||||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
|
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sqlite3_open_v2_(
|
||||||
|
const char *filename, /* Database filename (UTF-8) */
|
||||||
|
int filename_len,
|
||||||
|
int flags, /* Flags */
|
||||||
|
const char *zVfs, /* Name of VFS module to use */
|
||||||
|
int zVfs_len
|
||||||
|
) __EXPORT_NAME(sqlite3_open_v2) {
|
||||||
|
char *new_filename = (char *)malloc(filename_len + 1);
|
||||||
|
memcpy(new_filename, filename, filename_len);
|
||||||
|
new_filename[filename_len] = '\x00';
|
||||||
|
free((void *)filename);
|
||||||
|
|
||||||
|
char *new_zVfs = 0;
|
||||||
|
if (zVfs_len != 0) {
|
||||||
|
char *new_zVfs = (char *) malloc(zVfs_len + 1);
|
||||||
|
memcpy(new_zVfs, zVfs, zVfs_len);
|
||||||
|
new_zVfs[zVfs_len] = '\x00';
|
||||||
|
free((void *) zVfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3 *ppDb;
|
||||||
|
|
||||||
|
const int ret_code = sqlite3_open_v2(new_filename, &ppDb, (unsigned int)flags, new_zVfs);
|
||||||
|
free(new_filename);
|
||||||
|
free(new_zVfs);
|
||||||
|
|
||||||
|
int *result = (int *)malloc(16);
|
||||||
|
result[0] = ret_code;
|
||||||
|
result[2] = (int)ppDb;
|
||||||
|
|
||||||
|
set_result_ptr((char *)result);
|
||||||
|
}
|
||||||
|
|
||||||
int sqlite3_open_v2(
|
int sqlite3_open_v2(
|
||||||
const char *filename, /* Database filename (UTF-8) */
|
const char *filename, /* Database filename (UTF-8) */
|
||||||
sqlite3 **ppDb, /* OUT: SQLite db handle */
|
sqlite3 **ppDb, /* OUT: SQLite db handle */
|
||||||
int flags, /* Flags */
|
int flags, /* Flags */
|
||||||
const char *zVfs /* Name of VFS module to use */
|
const char *zVfs /* Name of VFS module to use */
|
||||||
){
|
) {
|
||||||
return openDatabase(filename, ppDb, (unsigned int)flags, zVfs);
|
return openDatabase(filename, ppDb, (unsigned int)flags, zVfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_UTF16
|
#ifndef SQLITE_OMIT_UTF16
|
||||||
/*
|
/*
|
||||||
** Open a new database handle.
|
** Open a new database handle.
|
||||||
|
@ -782,6 +782,27 @@ int sqlite3_prepare(
|
|||||||
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
|
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sqlite3_prepare_v2_(
|
||||||
|
sqlite3 *db, /* Database handle. */
|
||||||
|
const char *zSql, /* UTF-8 encoded SQL statement. */
|
||||||
|
int nBytes /* Length of zSql in bytes. */
|
||||||
|
) __EXPORT_NAME(sqlite3_prepare_v2) {
|
||||||
|
sqlite3_stmt *ppStmt;
|
||||||
|
const char *pzTail;
|
||||||
|
|
||||||
|
const int ret_code = sqlite3_prepare_v2(db, zSql, nBytes, &ppStmt, &pzTail);
|
||||||
|
free(zSql);
|
||||||
|
|
||||||
|
int *result = (int *)malloc(3*8);
|
||||||
|
result[0] = ret_code;
|
||||||
|
result[2] = (int)ppStmt;
|
||||||
|
result[4] = (int)pzTail;
|
||||||
|
result[5] = strlen(pzTail);
|
||||||
|
|
||||||
|
set_result_ptr((char *)result);
|
||||||
|
}
|
||||||
|
|
||||||
int sqlite3_prepare_v2(
|
int sqlite3_prepare_v2(
|
||||||
sqlite3 *db, /* Database handle. */
|
sqlite3 *db, /* Database handle. */
|
||||||
const char *zSql, /* UTF-8 encoded SQL statement. */
|
const char *zSql, /* UTF-8 encoded SQL statement. */
|
||||||
|
@ -34,6 +34,12 @@
|
|||||||
#define SQLITE3_H
|
#define SQLITE3_H
|
||||||
#include <stdarg.h> /* Needed for the definition of va_list */
|
#include <stdarg.h> /* Needed for the definition of va_list */
|
||||||
|
|
||||||
|
#define __EXPORT_NAME(name) \
|
||||||
|
__attribute__((export_name(#name)))
|
||||||
|
|
||||||
|
void set_result_ptr(const char *ptr);
|
||||||
|
void set_result_size(int size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Make sure we can call this stuff from C++.
|
** Make sure we can call this stuff from C++.
|
||||||
*/
|
*/
|
||||||
|
@ -1108,6 +1108,15 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
|
|||||||
** The following routines are used to access elements of the current row
|
** The following routines are used to access elements of the current row
|
||||||
** in the result set.
|
** in the result set.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void sqlite3_column_blob_(sqlite3_stmt *pStmt, int i) __EXPORT_NAME(sqlite3_column_blob) {
|
||||||
|
const char *result = sqlite3_column_blob(pStmt, i);
|
||||||
|
int blob_len = sqlite3_column_bytes(pStmt, i);
|
||||||
|
|
||||||
|
set_result_ptr((char *)result);
|
||||||
|
set_result_size(blob_len);
|
||||||
|
}
|
||||||
|
|
||||||
const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
|
const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
|
||||||
const void *val;
|
const void *val;
|
||||||
val = sqlite3_value_blob( columnMem(pStmt,i) );
|
val = sqlite3_value_blob( columnMem(pStmt,i) );
|
||||||
@ -1143,6 +1152,14 @@ sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
|
|||||||
columnMallocFailure(pStmt);
|
columnMallocFailure(pStmt);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sqlite3_column_text_(sqlite3_stmt *pStmt, int i) __EXPORT_NAME(sqlite3_column_text) {
|
||||||
|
const unsigned char *result = sqlite3_column_text(pStmt, i);
|
||||||
|
|
||||||
|
set_result_ptr((char *)result);
|
||||||
|
set_result_size(strlen(result));
|
||||||
|
}
|
||||||
|
|
||||||
const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
|
const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
|
||||||
const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
|
const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
|
||||||
columnMallocFailure(pStmt);
|
columnMallocFailure(pStmt);
|
||||||
@ -1235,6 +1252,13 @@ static const void *columnName(
|
|||||||
** Return the name of the Nth column of the result set returned by SQL
|
** Return the name of the Nth column of the result set returned by SQL
|
||||||
** statement pStmt.
|
** statement pStmt.
|
||||||
*/
|
*/
|
||||||
|
void sqlite3_column_name_(sqlite3_stmt *pStmt, int N) __EXPORT_NAME(sqlite3_column_name) {
|
||||||
|
const char *result = sqlite3_column_name(pStmt, N);
|
||||||
|
|
||||||
|
set_result_ptr((char *)result);
|
||||||
|
set_result_size(strlen(result));
|
||||||
|
}
|
||||||
|
|
||||||
const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
|
const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
|
||||||
return columnName(pStmt, N, 0, COLNAME_NAME);
|
return columnName(pStmt, N, 0, COLNAME_NAME);
|
||||||
}
|
}
|
||||||
@ -1407,6 +1431,21 @@ static int bindText(
|
|||||||
/*
|
/*
|
||||||
** Bind a blob value to an SQL statement variable.
|
** Bind a blob value to an SQL statement variable.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
int sqlite3_bind_blob_(
|
||||||
|
sqlite3_stmt *pStmt,
|
||||||
|
int i,
|
||||||
|
const void *zData,
|
||||||
|
int nData,
|
||||||
|
void (*xDel)(void*)
|
||||||
|
) __EXPORT_NAME(sqlite3_bind_blob) {
|
||||||
|
|
||||||
|
const int result = sqlite3_bind_blob(pStmt, i, zData, nData, xDel);
|
||||||
|
free((void *)zData);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int sqlite3_bind_blob(
|
int sqlite3_bind_blob(
|
||||||
sqlite3_stmt *pStmt,
|
sqlite3_stmt *pStmt,
|
||||||
int i,
|
int i,
|
||||||
@ -1483,7 +1522,21 @@ int sqlite3_bind_pointer(
|
|||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
int sqlite3_bind_text(
|
|
||||||
|
int sqlite3_bind_text_(
|
||||||
|
sqlite3_stmt *pStmt,
|
||||||
|
int i,
|
||||||
|
const char *zData,
|
||||||
|
int nData,
|
||||||
|
void (*xDel)(void*)
|
||||||
|
) __EXPORT_NAME(sqlite3_bind_text) {
|
||||||
|
const int result = sqlite3_bind_text(pStmt, i, zData, nData, xDel);
|
||||||
|
free((char *)zData);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sqlite3_bind_text(
|
||||||
sqlite3_stmt *pStmt,
|
sqlite3_stmt *pStmt,
|
||||||
int i,
|
int i,
|
||||||
const char *zData,
|
const char *zData,
|
||||||
|
131
src/wrapper.c
131
src/wrapper.c
@ -1,22 +1,10 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "../sdk/logger.h"
|
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
sqlite3 *state;
|
sqlite3 *state;
|
||||||
char *RESULT_PTR;
|
const char *RESULT_PTR;
|
||||||
int RESULT_SIZE;
|
int RESULT_SIZE;
|
||||||
|
|
||||||
int init() {
|
|
||||||
const int rc = sqlite3_initialize();
|
|
||||||
if(rc != 0) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sqlite3_open(":memory:", &state);
|
|
||||||
}
|
|
||||||
|
|
||||||
int g_isInited = 0;
|
|
||||||
|
|
||||||
void* allocate(size_t size) {
|
void* allocate(size_t size) {
|
||||||
return malloc(size + 1);
|
return malloc(size + 1);
|
||||||
}
|
}
|
||||||
@ -25,7 +13,7 @@ void deallocate(void *ptr, int size) {
|
|||||||
free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_result_ptr(char *ptr) {
|
void set_result_ptr(const char *ptr) {
|
||||||
RESULT_PTR = ptr;
|
RESULT_PTR = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,120 +25,7 @@ int get_result_size(void) {
|
|||||||
return RESULT_SIZE;
|
return RESULT_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *get_result_ptr() {
|
const char *get_result_ptr() {
|
||||||
return RESULT_PTR;
|
return RESULT_PTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct ShellText ShellText;
|
|
||||||
struct ShellText {
|
|
||||||
char *z;
|
|
||||||
int n;
|
|
||||||
int nAlloc;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void initText(ShellText *p){
|
|
||||||
memset(p, 0, sizeof(*p));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void freeText(ShellText *p){
|
|
||||||
free(p->z);
|
|
||||||
initText(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int strlen30(const char *z){
|
|
||||||
const char *z2 = z;
|
|
||||||
while( *z2 ){ z2++; }
|
|
||||||
return 0x3fffffff & (int)(z2 - z);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void appendText(ShellText *p, char const *zAppend, char quote){
|
|
||||||
int len;
|
|
||||||
int i;
|
|
||||||
int nAppend = strlen30(zAppend);
|
|
||||||
|
|
||||||
len = nAppend+p->n+1;
|
|
||||||
if( quote ){
|
|
||||||
len += 2;
|
|
||||||
for(i=0; i<nAppend; i++){
|
|
||||||
if( zAppend[i]==quote ) len++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( p->n+len>=p->nAlloc ){
|
|
||||||
p->nAlloc = p->nAlloc*2 + len + 20;
|
|
||||||
p->z = realloc(p->z, p->nAlloc);
|
|
||||||
// TODO: more solid work with OOM
|
|
||||||
if( p->z==0 ) __builtin_unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( quote ){
|
|
||||||
char *zCsr = p->z+p->n;
|
|
||||||
*zCsr++ = quote;
|
|
||||||
for(i=0; i<nAppend; i++){
|
|
||||||
*zCsr++ = zAppend[i];
|
|
||||||
if( zAppend[i]==quote ) *zCsr++ = quote;
|
|
||||||
}
|
|
||||||
*zCsr++ = quote;
|
|
||||||
p->n = (int)(zCsr - p->z);
|
|
||||||
*zCsr = '\0';
|
|
||||||
}else{
|
|
||||||
memcpy(p->z+p->n, zAppend, nAppend);
|
|
||||||
p->n += nAppend;
|
|
||||||
p->z[p->n] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int captureOutputCallback(void *pArg, int nArg, char **azArg, char **az){
|
|
||||||
ShellText *p = (ShellText*)pArg;
|
|
||||||
int i;
|
|
||||||
UNUSED_PARAMETER(az);
|
|
||||||
if( azArg==0 ) return 0;
|
|
||||||
if( p->n ) appendText(p, "|", 0);
|
|
||||||
for(i=0; i<nArg; i++){
|
|
||||||
if( i ) appendText(p, ",", 0);
|
|
||||||
if( azArg[i] ) appendText(p, azArg[i], 0);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void invoke(char *request, int request_size) {
|
|
||||||
if(g_isInited == 0) {
|
|
||||||
// TODO: check the return code
|
|
||||||
init();
|
|
||||||
|
|
||||||
#if LOG_ENABLED
|
|
||||||
const char successInitMessage[] = "Sqlite has been initialized\n";
|
|
||||||
log_utf8_string(successInitMessage, sizeof(successInitMessage));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
g_isInited = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
request[request_size] = 0;
|
|
||||||
|
|
||||||
#if LOG_ENABLED
|
|
||||||
log_utf8_string(request, request_size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ShellText str;
|
|
||||||
initText(&str);
|
|
||||||
char *errorMessage = 0;
|
|
||||||
|
|
||||||
int rc = sqlite3_exec(state, request, captureOutputCallback, &str, &errorMessage);
|
|
||||||
|
|
||||||
char *response = 0;
|
|
||||||
if(rc || errorMessage) {
|
|
||||||
RESULT_PTR = errorMessage;
|
|
||||||
RESULT_SIZE = strlen(errorMessage);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(str.n != 0) {
|
|
||||||
RESULT_PTR = str.z;
|
|
||||||
RESULT_SIZE = str.n;
|
|
||||||
} else {
|
|
||||||
// if a request was successfull, sqlite doesn't return anything as the result string
|
|
||||||
RESULT_PTR = strdup("OK");
|
|
||||||
RESULT_SIZE = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user