8 Commits

Author SHA1 Message Date
vms
15384f3ab1 Merge pull request #1 from fluencelabs/add_demo_vfs
Add demo vfs
2021-03-04 14:05:19 +03:00
vms
c6e4a30f40 enable WASI 2021-03-04 14:04:48 +03:00
vms
5660a45c22 uncomment stuff in memdb 2021-03-03 15:13:00 +03:00
vms
1765640d12 add demo vfs 2021-03-03 15:07:51 +03:00
vms
cb62ab800e fix sqlite3_bind_blob 2021-01-28 00:13:52 +03:00
vms
4179ccd6f9 fix blob/text setters and getters 2020-11-09 04:39:38 +03:00
vms
df5cbd0b0f make Dockerfile compatible with fce 0.1.11 2020-11-08 18:30:24 +03:00
vms
43bd1080a2 make compatible with sqlite-wasm-connector 2020-09-17 21:20:05 +03:00
13 changed files with 1361 additions and 197 deletions

View File

@ -2,5 +2,5 @@ modules_dir = "./"
[[module]]
name = "sqlite3"
mem_pages_count = 100
mem_pages_count = 1000
logger_enabled = true

View File

@ -4,9 +4,12 @@ RUN apt-get update \
&& apt-get install -y ca-certificates \
curl \
git \
make
make \
cargo
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 /
RUN cargo install fcli --version 0.1.12
VOLUME /code
WORKDIR /code

View File

@ -2,8 +2,9 @@ TARGET = sqlite3
CC = /bin/clang
SYSROOT = /share/wasi-sysroot
TARGET_TRIPLE = wasm32-wasi
CFLAGS = -nostartfiles -fvisibility=hidden
LDFLAGS = -Wl,--no-entry,--demangle,--allow-undefined
CFLAGS = -fvisibility=hidden
SDK = sdk/logger.h
LDFLAGS = -Wl,--demangle,--allow-undefined
EXPORT_FUNCS = \
--export=allocate,$\
--export=deallocate,$\
@ -11,7 +12,32 @@ EXPORT_FUNCS = \
--export=set_result_ptr,$\
--export=get_result_size,$\
--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 = \
src/alter.c\
src/analyze.c\
@ -26,6 +52,8 @@ SQLITE_SRC = \
src/complete.c\
src/ctime.c\
src/date.c\
src/demo_os.c\
src/demo_vfs.c\
src/dbpage.c\
src/dbstat.c\
src/delete.c\
@ -110,6 +138,7 @@ SQLITE_FLAGS = \
-DENABLE_LOG\
-DBUILD_sqlite\
-DNDEBUG\
-DSQLITE_OS_UNIX\
-DSQLITE_THREADSAFE=0\
-DHAVE_READLINE=0\
-DHAVE_EDITLINE=0\
@ -134,6 +163,7 @@ all: default
$(TARGET): $(SQLITE_SRC) $(WRAPPER_SRC)
$(CC) -O3 --sysroot=$(SYSROOT) --target=$(TARGET_TRIPLE) $(SQLITE_FLAGS) $(CFLAGS) $(LDFLAGS) -Wl,$(EXPORT_FUNCS) $^ -o $@.wasm
/root/.cargo/bin/fce embed -i sqlite3.wasm -w sqlite3.wit
.PRECIOUS: $(TARGET)

View File

@ -1,43 +1,458 @@
;; Fluence SQLite fork Wasm Interface Types
;; Types
(@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)
(result record 8))) ;; 17
(@interface type (func
(param $filename: string $flags: s32 $vfs: string)
(result record 8))) ;; 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)
(result record 7))) ;; 37
(@interface type (func
(param $db_handle: u32 $sql: string)
(result record 7))) ;; 38
(@interface type (func
(param $stmt_handle: u32)
(result s32))) ;; 39
(@interface type (func
(param $stmt_handle: u32)
(result s32))) ;; 40
(@interface type (func
(param $stmt_handle: u32 $pos: s32)
(result s32))) ;; 41
(@interface type (func
(param $stmt_handle: u32 $pos: s32)
(result s32))) ;; 42
(@interface type (func
(param $stmt_handle: u32 $pos: s32 $blob: array (u8) $xDel: s32)
(result s32))) ;; 43
(@interface type (func
(param $stmt_handle: u32 $pos: s32 $blob: array (u8) $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)
(result record 6))) ;; 51
(@interface type (func
(param $db_handle: u32 $sql: string $callback_id: s32 $callback_arg: s32)
(result record 6))) ;; 52
(@interface type (func
(result s32))) ;; 53
(@interface type (func
(result s32))) ;; 54
(@interface type (func
(param $stmt_handle: u32 $icol: s32)
(result array (u8)))) ;; 55
(@interface type (func
(param $stmt_handle: u32 $icol: s32)
(result array (u8)))) ;; 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
;; allocate
(@interface type (func (param $size: i32) (result i32))) ;; 0
;; deallocate
(@interface type (func (param $pointer: i32 $size: i32))) ;; 1
;; invoke
(@interface type (func (param $request: string) (result string))) ;; 2
;; Adapters
(@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
call-core 21
s32.from_i32)
(@interface func (type 41)
arg.get 0
i32.from_u32
arg.get 1
i32.from_s32
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
array.lower_memory u8
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
array.lift_memory u8)
(@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)
;; get_result_ptr/get_result_size
(@interface type (func (result i32))) ;; 3
;; set_result_ptr/set_result_size
(@interface type (func (param $result: i32))) ;; 4
(@interface export "allocate" (func 0)) ;; 0
(@interface export "deallocate" (func 1)) ;; 1
(@interface export "invoke" (func 2)) ;; 2
(@interface export "get_result_size" (func 3)) ;; 3
(@interface export "get_result_ptr" (func 3)) ;; 4
(@interface export "set_result_size" (func 4)) ;; 5
(@interface export "set_result_ptr" (func 4)) ;; 6
;; adapter for export invoke function
(@interface func (type 2)
arg.get 0
string.size
call-core 0 ;; call allocate
arg.get 0
string.lower_memory
call-core 2 ;; call invoke
call-core 4 ;; call get_result_size
call-core 3 ;; call get_result_ptr
string.lift_memory
call-core 4 ;; call get_result_size
call-core 3 ;; call get_result_ptr
call-core 1 ;; call deallocate
)
;; Exports
(@interface export "allocate" (func 0))
(@interface export "deallocate" (func 1))
(@interface export "get_result_size" (func 2))
(@interface export "get_result_ptr" (func 3))
(@interface export "set_result_size" (func 4))
(@interface export "set_result_ptr" (func 5))
(@interface export "sqlite3_column_text" (func 10))
(@interface export "sqlite3_column_bytes" (func 12))
(@interface export "sqlite3_close" (func 14))
(@interface export "sqlite3_bind_double" (func 16))
(@interface export "sqlite3_open_v2" (func 18))
(@interface export "sqlite3_changes" (func 20))
(@interface export "sqlite3_step" (func 22))
(@interface export "sqlite3_column_int64" (func 24))
(@interface export "sqlite3_errcode" (func 26))
(@interface export "sqlite3_column_double" (func 28))
(@interface export "sqlite3_busy_timeout" (func 30))
(@interface export "sqlite3_errmsg" (func 32))
(@interface export "sqlite3_bind_int64" (func 34))
(@interface export "sqlite3_finalize" (func 36))
(@interface export "sqlite3_prepare_v2" (func 38))
(@interface export "sqlite3_column_count" (func 40))
(@interface export "sqlite3_bind_null" (func 42))
(@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
(@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))

12
src/demo_os.c Normal file
View File

@ -0,0 +1,12 @@
#include "sqlite3.h"
extern sqlite3_vfs *sqlite3_demovfs(void);
int sqlite3_os_init() {
sqlite3_vfs_register(sqlite3_demovfs(), 0);
return SQLITE_OK;
}
int sqlite3_os_end() {
return SQLITE_OK;
}

679
src/demo_vfs.c Normal file
View File

@ -0,0 +1,679 @@
/*
** 2010 April 7
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file implements an example of a simple VFS implementation that
** omits complex features often not required or not possible on embedded
** platforms. Code is included to buffer writes to the journal file,
** which can be a significant performance improvement on some embedded
** platforms.
**
** OVERVIEW
**
** The code in this file implements a minimal SQLite VFS that can be
** used on Linux and other posix-like operating systems. The following
** system calls are used:
**
** File-system: access(), unlink(), getcwd()
** File IO: open(), read(), write(), fsync(), close(), fstat()
** Other: sleep(), usleep(), time()
**
** The following VFS features are omitted:
**
** 1. File locking. The user must ensure that there is at most one
** connection to each database when using this VFS. Multiple
** connections to a single shared-cache count as a single connection
** for the purposes of the previous statement.
**
** 2. The loading of dynamic extensions (shared libraries).
**
** 3. Temporary files. The user must configure SQLite to use in-memory
** temp files when using this VFS. The easiest way to do this is to
** compile with:
**
** -DSQLITE_TEMP_STORE=3
**
** 4. File truncation. As of version 3.6.24, SQLite may run without
** a working xTruncate() call, providing the user does not configure
** SQLite to use "journal_mode=truncate", or use both
** "journal_mode=persist" and ATTACHed databases.
**
** It is assumed that the system uses UNIX-like path-names. Specifically,
** that '/' characters are used to separate path components and that
** a path-name is a relative path unless it begins with a '/'. And that
** no UTF-8 encoded paths are greater than 512 bytes in length.
**
** JOURNAL WRITE-BUFFERING
**
** To commit a transaction to the database, SQLite first writes rollback
** information into the journal file. This usually consists of 4 steps:
**
** 1. The rollback information is sequentially written into the journal
** file, starting at the start of the file.
** 2. The journal file is synced to disk.
** 3. A modification is made to the first few bytes of the journal file.
** 4. The journal file is synced to disk again.
**
** Most of the data is written in step 1 using a series of calls to the
** VFS xWrite() method. The buffers passed to the xWrite() calls are of
** various sizes. For example, as of version 3.6.24, when committing a
** transaction that modifies 3 pages of a database file that uses 4096
** byte pages residing on a media with 512 byte sectors, SQLite makes
** eleven calls to the xWrite() method to create the rollback journal,
** as follows:
**
** Write offset | Bytes written
** ----------------------------
** 0 512
** 512 4
** 516 4096
** 4612 4
** 4616 4
** 4620 4096
** 8716 4
** 8720 4
** 8724 4096
** 12820 4
** ++++++++++++SYNC+++++++++++
** 0 12
** ++++++++++++SYNC+++++++++++
**
** On many operating systems, this is an efficient way to write to a file.
** However, on some embedded systems that do not cache writes in OS
** buffers it is much more efficient to write data in blocks that are
** an integer multiple of the sector-size in size and aligned at the
** start of a sector.
**
** To work around this, the code in this file allocates a fixed size
** buffer of SQLITE_DEMOVFS_BUFFERSZ using sqlite3_malloc() whenever a
** journal file is opened. It uses the buffer to coalesce sequential
** writes into aligned SQLITE_DEMOVFS_BUFFERSZ blocks. When SQLite
** invokes the xSync() method to sync the contents of the file to disk,
** all accumulated data is written out, even if it does not constitute
** a complete block. This means the actual IO to create the rollback
** journal for the example transaction above is this:
**
** Write offset | Bytes written
** ----------------------------
** 0 8192
** 8192 4632
** ++++++++++++SYNC+++++++++++
** 0 12
** ++++++++++++SYNC+++++++++++
**
** Much more efficient if the underlying OS is not caching write
** operations.
*/
#if !defined(SQLITE_TEST) || SQLITE_OS_UNIX
#include "sqlite3.h"
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/param.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
/*
** Size of the write buffer used by journal files in bytes.
*/
#ifndef SQLITE_DEMOVFS_BUFFERSZ
# define SQLITE_DEMOVFS_BUFFERSZ 8192
#endif
/*
** The maximum pathname length supported by this VFS.
*/
#define MAXPATHNAME 512
/*
** When using this VFS, the sqlite3_file* handles that SQLite uses are
** actually pointers to instances of type DemoFile.
*/
typedef struct DemoFile DemoFile;
struct DemoFile {
sqlite3_file base; /* Base class. Must be first. */
int fd; /* File descriptor */
char *aBuffer; /* Pointer to malloc'd buffer */
int nBuffer; /* Valid bytes of data in zBuffer */
sqlite3_int64 iBufferOfst; /* Offset in file of zBuffer[0] */
};
/*
** Write directly to the file passed as the first argument. Even if the
** file has a write-buffer (DemoFile.aBuffer), ignore it.
*/
static int demoDirectWrite(
DemoFile *p, /* File handle */
const void *zBuf, /* Buffer containing data to write */
int iAmt, /* Size of data to write in bytes */
sqlite_int64 iOfst /* File offset to write to */
){
off_t ofst; /* Return value from lseek() */
size_t nWrite; /* Return value from write() */
ofst = lseek(p->fd, iOfst, SEEK_SET);
if( ofst!=iOfst ){
return SQLITE_IOERR_WRITE;
}
nWrite = write(p->fd, zBuf, iAmt);
if( nWrite!=iAmt ){
return SQLITE_IOERR_WRITE;
}
return SQLITE_OK;
}
/*
** Flush the contents of the DemoFile.aBuffer buffer to disk. This is a
** no-op if this particular file does not have a buffer (i.e. it is not
** a journal file) or if the buffer is currently empty.
*/
static int demoFlushBuffer(DemoFile *p){
int rc = SQLITE_OK;
if( p->nBuffer ){
rc = demoDirectWrite(p, p->aBuffer, p->nBuffer, p->iBufferOfst);
p->nBuffer = 0;
}
return rc;
}
/*
** Close a file.
*/
static int demoClose(sqlite3_file *pFile){
int rc;
DemoFile *p = (DemoFile*)pFile;
rc = demoFlushBuffer(p);
sqlite3_free(p->aBuffer);
close(p->fd);
return rc;
}
/*
** Read data from a file.
*/
static int demoRead(
sqlite3_file *pFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
DemoFile *p = (DemoFile*)pFile;
off_t ofst; /* Return value from lseek() */
int nRead; /* Return value from read() */
int rc; /* Return code from demoFlushBuffer() */
/* Flush any data in the write buffer to disk in case this operation
** is trying to read data the file-region currently cached in the buffer.
** It would be possible to detect this case and possibly save an
** unnecessary write here, but in practice SQLite will rarely read from
** a journal file when there is data cached in the write-buffer.
*/
rc = demoFlushBuffer(p);
if( rc!=SQLITE_OK ){
return rc;
}
ofst = lseek(p->fd, iOfst, SEEK_SET);
if( ofst!=iOfst ){
return SQLITE_IOERR_READ;
}
nRead = read(p->fd, zBuf, iAmt);
if( nRead==iAmt ){
return SQLITE_OK;
}else if( nRead>=0 ){
return SQLITE_IOERR_SHORT_READ;
}
return SQLITE_IOERR_READ;
}
/*
** Write data to a crash-file.
*/
static int demoWrite(
sqlite3_file *pFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
DemoFile *p = (DemoFile*)pFile;
if( p->aBuffer ){
char *z = (char *)zBuf; /* Pointer to remaining data to write */
int n = iAmt; /* Number of bytes at z */
sqlite3_int64 i = iOfst; /* File offset to write to */
while( n>0 ){
int nCopy; /* Number of bytes to copy into buffer */
/* If the buffer is full, or if this data is not being written directly
** following the data already buffered, flush the buffer. Flushing
** the buffer is a no-op if it is empty.
*/
if( p->nBuffer==SQLITE_DEMOVFS_BUFFERSZ || p->iBufferOfst+p->nBuffer!=i ){
int rc = demoFlushBuffer(p);
if( rc!=SQLITE_OK ){
return rc;
}
}
assert( p->nBuffer==0 || p->iBufferOfst+p->nBuffer==i );
p->iBufferOfst = i - p->nBuffer;
/* Copy as much data as possible into the buffer. */
nCopy = SQLITE_DEMOVFS_BUFFERSZ - p->nBuffer;
if( nCopy>n ){
nCopy = n;
}
memcpy(&p->aBuffer[p->nBuffer], z, nCopy);
p->nBuffer += nCopy;
n -= nCopy;
i += nCopy;
z += nCopy;
}
}else{
return demoDirectWrite(p, zBuf, iAmt, iOfst);
}
return SQLITE_OK;
}
/*
** Truncate a file. This is a no-op for this VFS (see header comments at
** the top of the file).
*/
static int demoTruncate(sqlite3_file *pFile, sqlite_int64 size){
#if 0
if( ftruncate(((DemoFile *)pFile)->fd, size) ) return SQLITE_IOERR_TRUNCATE;
#endif
return SQLITE_OK;
}
/*
** Sync the contents of the file to the persistent media.
*/
static int demoSync(sqlite3_file *pFile, int flags){
DemoFile *p = (DemoFile*)pFile;
int rc;
rc = demoFlushBuffer(p);
if( rc!=SQLITE_OK ){
return rc;
}
rc = fsync(p->fd);
return (rc==0 ? SQLITE_OK : SQLITE_IOERR_FSYNC);
}
/*
** Write the size of the file in bytes to *pSize.
*/
static int demoFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
DemoFile *p = (DemoFile*)pFile;
int rc; /* Return code from fstat() call */
struct stat sStat; /* Output of fstat() call */
/* Flush the contents of the buffer to disk. As with the flush in the
** demoRead() method, it would be possible to avoid this and save a write
** here and there. But in practice this comes up so infrequently it is
** not worth the trouble.
*/
rc = demoFlushBuffer(p);
if( rc!=SQLITE_OK ){
return rc;
}
rc = fstat(p->fd, &sStat);
if( rc!=0 ) return SQLITE_IOERR_FSTAT;
*pSize = sStat.st_size;
return SQLITE_OK;
}
/*
** Locking functions. The xLock() and xUnlock() methods are both no-ops.
** The xCheckReservedLock() always indicates that no other process holds
** a reserved lock on the database file. This ensures that if a hot-journal
** file is found in the file-system it is rolled back.
*/
static int demoLock(sqlite3_file *pFile, int eLock){
return SQLITE_OK;
}
static int demoUnlock(sqlite3_file *pFile, int eLock){
return SQLITE_OK;
}
static int demoCheckReservedLock(sqlite3_file *pFile, int *pResOut){
*pResOut = 0;
return SQLITE_OK;
}
/*
** No xFileControl() verbs are implemented by this VFS.
*/
static int demoFileControl(sqlite3_file *pFile, int op, void *pArg){
return SQLITE_OK;
}
/*
** The xSectorSize() and xDeviceCharacteristics() methods. These two
** may return special values allowing SQLite to optimize file-system
** access to some extent. But it is also safe to simply return 0.
*/
static int demoSectorSize(sqlite3_file *pFile){
return 0;
}
static int demoDeviceCharacteristics(sqlite3_file *pFile){
return 0;
}
/*
** Open a file handle.
*/
static int demoOpen(
sqlite3_vfs *pVfs, /* VFS */
const char *zName, /* File to open, or 0 for a temp file */
sqlite3_file *pFile, /* Pointer to DemoFile struct to populate */
int flags, /* Input SQLITE_OPEN_XXX flags */
int *pOutFlags /* Output SQLITE_OPEN_XXX flags (or NULL) */
){
static const sqlite3_io_methods demoio = {
1, /* iVersion */
demoClose, /* xClose */
demoRead, /* xRead */
demoWrite, /* xWrite */
demoTruncate, /* xTruncate */
demoSync, /* xSync */
demoFileSize, /* xFileSize */
demoLock, /* xLock */
demoUnlock, /* xUnlock */
demoCheckReservedLock, /* xCheckReservedLock */
demoFileControl, /* xFileControl */
demoSectorSize, /* xSectorSize */
demoDeviceCharacteristics /* xDeviceCharacteristics */
};
DemoFile *p = (DemoFile*)pFile; /* Populate this structure */
int oflags = 0; /* flags to pass to open() call */
char *aBuf = 0;
if( zName==0 ){
return SQLITE_IOERR;
}
if( flags&SQLITE_OPEN_MAIN_JOURNAL ){
aBuf = (char *)sqlite3_malloc(SQLITE_DEMOVFS_BUFFERSZ);
if( !aBuf ){
return SQLITE_NOMEM;
}
}
if( flags&SQLITE_OPEN_EXCLUSIVE ) oflags |= O_EXCL;
if( flags&SQLITE_OPEN_CREATE ) oflags |= O_CREAT;
if( flags&SQLITE_OPEN_READONLY ) oflags |= O_RDONLY;
if( flags&SQLITE_OPEN_READWRITE ) oflags |= O_RDWR;
memset(p, 0, sizeof(DemoFile));
p->fd = open(zName, oflags, 0600);
if( p->fd<0 ){
sqlite3_free(aBuf);
return SQLITE_CANTOPEN;
}
p->aBuffer = aBuf;
if( pOutFlags ){
*pOutFlags = flags;
}
p->base.pMethods = &demoio;
return SQLITE_OK;
}
/*
** Delete the file identified by argument zPath. If the dirSync parameter
** is non-zero, then ensure the file-system modification to delete the
** file has been synced to disk before returning.
*/
static int demoDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
int rc; /* Return code */
rc = unlink(zPath);
if( rc!=0 && errno==ENOENT ) return SQLITE_OK;
if( rc==0 && dirSync ){
int dfd; /* File descriptor open on directory */
int i; /* Iterator variable */
char zDir[MAXPATHNAME+1]; /* Name of directory containing file zPath */
/* Figure out the directory name from the path of the file deleted. */
sqlite3_snprintf(MAXPATHNAME, zDir, "%s", zPath);
zDir[MAXPATHNAME] = '\0';
for(i=strlen(zDir); i>1 && zDir[i]!='/'; i++);
zDir[i] = '\0';
/* Open a file-descriptor on the directory. Sync. Close. */
dfd = open(zDir, O_RDONLY, 0);
if( dfd<0 ){
rc = -1;
}else{
rc = fsync(dfd);
close(dfd);
}
}
return (rc==0 ? SQLITE_OK : SQLITE_IOERR_DELETE);
}
#ifndef F_OK
# define F_OK 0
#endif
#ifndef R_OK
# define R_OK 4
#endif
#ifndef W_OK
# define W_OK 2
#endif
/*
** Query the file-system to see if the named file exists, is readable or
** is both readable and writable.
*/
static int demoAccess(
sqlite3_vfs *pVfs,
const char *zPath,
int flags,
int *pResOut
){
int rc; /* access() return code */
int eAccess = F_OK; /* Second argument to access() */
assert( flags==SQLITE_ACCESS_EXISTS /* access(zPath, F_OK) */
|| flags==SQLITE_ACCESS_READ /* access(zPath, R_OK) */
|| flags==SQLITE_ACCESS_READWRITE /* access(zPath, R_OK|W_OK) */
);
if( flags==SQLITE_ACCESS_READWRITE ) eAccess = R_OK|W_OK;
if( flags==SQLITE_ACCESS_READ ) eAccess = R_OK;
rc = access(zPath, eAccess);
*pResOut = (rc==0);
return SQLITE_OK;
}
/*
** Argument zPath points to a nul-terminated string containing a file path.
** If zPath is an absolute path, then it is copied as is into the output
** buffer. Otherwise, if it is a relative path, then the equivalent full
** path is written to the output buffer.
**
** This function assumes that paths are UNIX style. Specifically, that:
**
** 1. Path components are separated by a '/'. and
** 2. Full paths begin with a '/' character.
*/
static int demoFullPathname(
sqlite3_vfs *pVfs, /* VFS */
const char *zPath, /* Input path (possibly a relative path) */
int nPathOut, /* Size of output buffer in bytes */
char *zPathOut /* Pointer to output buffer */
){
sqlite3_snprintf(nPathOut, zPathOut, "%s", zPath);
zPathOut[nPathOut-1] = '\0';
return SQLITE_OK;
}
/*
** The following four VFS methods:
**
** xDlOpen
** xDlError
** xDlSym
** xDlClose
**
** are supposed to implement the functionality needed by SQLite to load
** extensions compiled as shared objects. This simple VFS does not support
** this functionality, so the following functions are no-ops.
*/
static void *demoDlOpen(sqlite3_vfs *pVfs, const char *zPath){
return 0;
}
static void demoDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
sqlite3_snprintf(nByte, zErrMsg, "Loadable extensions are not supported");
zErrMsg[nByte-1] = '\0';
}
static void (*demoDlSym(sqlite3_vfs *pVfs, void *pH, const char *z))(void){
return 0;
}
static void demoDlClose(sqlite3_vfs *pVfs, void *pHandle){
return;
}
/*
** Parameter zByte points to a buffer nByte bytes in size. Populate this
** buffer with pseudo-random data.
*/
static int demoRandomness(sqlite3_vfs *pVfs, int nByte, char *zByte){
return SQLITE_OK;
}
/*
** Sleep for at least nMicro microseconds. Return the (approximate) number
** of microseconds slept for.
*/
static int demoSleep(sqlite3_vfs *pVfs, int nMicro){
sleep(nMicro / 1000000);
usleep(nMicro % 1000000);
return nMicro;
}
/*
** Set *pTime to the current UTC time expressed as a Julian day. Return
** SQLITE_OK if successful, or an error code otherwise.
**
** http://en.wikipedia.org/wiki/Julian_day
**
** This implementation is not very good. The current time is rounded to
** an integer number of seconds. Also, assuming time_t is a signed 32-bit
** value, it will stop working some time in the year 2038 AD (the so-called
** "year 2038" problem that afflicts systems that store time this way).
*/
static int demoCurrentTime(sqlite3_vfs *pVfs, double *pTime){
time_t t = time(0);
*pTime = t/86400.0 + 2440587.5;
return SQLITE_OK;
}
/*
** This function returns a pointer to the VFS implemented in this file.
** To make the VFS available to SQLite:
**
** sqlite3_vfs_register(sqlite3_demovfs(), 0);
*/
sqlite3_vfs *sqlite3_demovfs(void){
static sqlite3_vfs demovfs = {
1, /* iVersion */
sizeof(DemoFile), /* szOsFile */
MAXPATHNAME, /* mxPathname */
0, /* pNext */
"demo", /* zName */
0, /* pAppData */
demoOpen, /* xOpen */
demoDelete, /* xDelete */
demoAccess, /* xAccess */
demoFullPathname, /* xFullPathname */
demoDlOpen, /* xDlOpen */
demoDlError, /* xDlError */
demoDlSym, /* xDlSym */
demoDlClose, /* xDlClose */
demoRandomness, /* xRandomness */
demoSleep, /* xSleep */
demoCurrentTime, /* xCurrentTime */
};
return &demovfs;
}
#endif /* !defined(SQLITE_TEST) || SQLITE_OS_UNIX */
#ifdef SQLITE_TEST
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
#if SQLITE_OS_UNIX
static int SQLITE_TCLAPI register_demovfs(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
sqlite3_vfs_register(sqlite3_demovfs(), 1);
return TCL_OK;
}
static int SQLITE_TCLAPI unregister_demovfs(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
sqlite3_vfs_unregister(sqlite3_demovfs());
return TCL_OK;
}
/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest_demovfs_Init(Tcl_Interp *interp){
Tcl_CreateObjCommand(interp, "register_demovfs", register_demovfs, 0, 0);
Tcl_CreateObjCommand(interp, "unregister_demovfs", unregister_demovfs, 0, 0);
return TCL_OK;
}
#else
int Sqlitetest_demovfs_Init(Tcl_Interp *interp){ return TCL_OK; }
#endif
#endif /* SQLITE_TEST */

View File

@ -16,6 +16,7 @@
*/
#include "sqliteInt.h"
#include <string.h>
/*
** Execute SQL code. Return one of the SQLITE_ success/failure
@ -27,6 +28,33 @@
** argument to xCallback(). If xCallback=NULL then no callback
** 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(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */

View File

@ -16,6 +16,9 @@
*/
#include "sqliteInt.h"
extern char *RESULT_PTR;
extern int RESULT_SIZE;
#ifdef SQLITE_ENABLE_FTS3
# include "fts3.h"
#endif
@ -237,9 +240,7 @@ int sqlite3_initialize(void){
}
if( rc==SQLITE_OK ){
sqlite3GlobalConfig.isPCacheInit = 1;
#if __sqlite_unmodified_upstream
rc = sqlite3OsInit();
#endif
}
#ifdef SQLITE_ENABLE_DESERIALIZE
if( rc==SQLITE_OK ){
@ -323,9 +324,7 @@ int sqlite3_shutdown(void){
void SQLITE_EXTRA_SHUTDOWN(void);
SQLITE_EXTRA_SHUTDOWN();
#endif
#if __sqlite_unmodified_upstream
sqlite3_os_end();
#endif
sqlite3_reset_auto_extension();
sqlite3GlobalConfig.isInit = 0;
}
@ -2450,6 +2449,13 @@ int sqlite3TempInMemory(const sqlite3 *db){
** Return UTF-8 encoded English language explanation of the most recent
** 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 *z;
if( !db ){
@ -3428,15 +3434,50 @@ int sqlite3_open(
return openDatabase(zFilename, ppDb,
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(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
const char *zVfs /* Name of VFS module to use */
){
) {
return openDatabase(filename, ppDb, (unsigned int)flags, zVfs);
}
#ifndef SQLITE_OMIT_UTF16
/*
** Open a new database handle.

View File

@ -17,10 +17,7 @@
** sqlite3_deserialize().
*/
#include "sqliteInt.h"
#if __sqlite_unmodified_upstream
#else
#include <stdlib.h>
#endif
#ifdef SQLITE_ENABLE_DESERIALIZE
/*
@ -426,15 +423,7 @@ static void memdbDlClose(sqlite3_vfs *pVfs, void *pHandle){
** random data.
*/
static int memdbRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
#if __sqlite_unmodified_upstream
return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
#else
zBufOut = malloc(nByte);
for(int i = 0; i < nByte; ++i) {
zBufOut[i] = rand() % 256;
}
return SQLITE_OK;
#endif
}
/*
@ -622,23 +611,14 @@ end_deserialize:
** Register the new VFS.
*/
int sqlite3MemdbInit(void){
#if __sqlite_unmodified_upstream
sqlite3_vfs *pLower = sqlite3_vfs_find(0);
int sz = pLower->szOsFile;
memdb_vfs.pAppData = pLower;
#else
memdb_vfs.pAppData = (void *)0xFFFFFFFF;
int sz = sizeof(MemFile);
#endif
/* In all known configurations of SQLite, the size of a default
** sqlite3_file is greater than the size of a memdb sqlite3_file.
** Should that ever change, remove the following NEVER() */
if( NEVER(sz<sizeof(MemFile)) ) sz = sizeof(MemFile);
memdb_vfs.szOsFile = sz;
#if __sqlite_unmodified_upstream
return sqlite3_vfs_register(&memdb_vfs, 0);
#else
return sqlite3_vfs_register(&memdb_vfs, 1);
#endif
}
#endif /* SQLITE_ENABLE_DESERIALIZE */

View File

@ -782,6 +782,27 @@ int sqlite3_prepare(
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
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((void *)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(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */

View File

@ -34,6 +34,12 @@
#define SQLITE3_H
#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++.
*/

View File

@ -1108,6 +1108,18 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
** The following routines are used to access elements of the current row
** in the result set.
*/
void sqlite3_column_blob_(sqlite3_stmt *pStmt, int i) __EXPORT_NAME(sqlite3_column_blob) {
const char *blob = sqlite3_column_blob(pStmt, i);
int blob_len = sqlite3_column_bytes(pStmt, i);
unsigned char *copied_result = malloc(blob_len);
memcpy(copied_result, blob, blob_len);
set_result_ptr((char *)copied_result);
set_result_size(blob_len);
}
const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
const void *val;
val = sqlite3_value_blob( columnMem(pStmt,i) );
@ -1143,6 +1155,18 @@ sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
columnMallocFailure(pStmt);
return val;
}
void sqlite3_column_text_(sqlite3_stmt *pStmt, int i) __EXPORT_NAME(sqlite3_column_text) {
const unsigned char *text = sqlite3_column_text(pStmt, i);
const unsigned int text_len = sqlite3_column_bytes(pStmt, i);
unsigned char *copied_text = malloc(text_len);
memcpy(copied_text, text, text_len);
set_result_ptr((char *)copied_text);
set_result_size(text_len);
}
const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
@ -1235,6 +1259,13 @@ static const void *columnName(
** Return the name of the Nth column of the result set returned by SQL
** 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){
return columnName(pStmt, N, 0, COLNAME_NAME);
}
@ -1407,6 +1438,30 @@ static int bindText(
/*
** Bind a blob value to an SQL statement variable.
*/
int sqlite3_bind_blob_(
sqlite3_stmt *pStmt,
int i,
char *zData,
int nData,
void (*xDel)(void*)
) __EXPORT_NAME(sqlite3_bind_blob) {
const int copied_nData = nData / 8;
char *copied_zData = malloc(copied_nData);
if (copied_zData == 0) {
return -1;
}
for (int char_id = 0; char_id < copied_nData; ++char_id) {
copied_zData[char_id] = zData[char_id * 8];
}
const int result = sqlite3_bind_blob(pStmt, i, copied_zData, copied_nData, 0);
return result;
}
int sqlite3_bind_blob(
sqlite3_stmt *pStmt,
int i,
@ -1483,7 +1538,23 @@ int sqlite3_bind_pointer(
}
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) {
char *copied_zData = malloc(nData);
memcpy(copied_zData, zData, nData);
const int result = sqlite3_bind_text(pStmt, i, copied_zData, nData, xDel);
return result;
}
int sqlite3_bind_text(
sqlite3_stmt *pStmt,
int i,
const char *zData,

View File

@ -1,22 +1,9 @@
#include <stdlib.h>
#include "../sdk/logger.h"
#include "sqliteInt.h"
sqlite3 *state;
char *RESULT_PTR;
const char *RESULT_PTR;
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) {
return malloc(size + 1);
}
@ -25,7 +12,7 @@ void deallocate(void *ptr, int size) {
free(ptr);
}
void set_result_ptr(char *ptr) {
void set_result_ptr(const char *ptr) {
RESULT_PTR = ptr;
}
@ -37,120 +24,11 @@ int get_result_size(void) {
return RESULT_SIZE;
}
char *get_result_ptr() {
const char *get_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);
}
int main() {
// the main purpose of this empty main is to initialize WASi subsystem
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;
}
}
}
}