Skip to content

Changes from jlongers fork (for absurd-sql) and makefile fix #608

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ EMFLAGS_DEBUG = \
-s ASSERTIONS=2 \
-O1

BITCODE_FILES = out/sqlite3.o out/extension-functions.o
BITCODE_FILES = out/sqlite3.o out/extension-functions.o out/vfs.o

OUTPUT_WRAPPER_FILES = src/shell-pre.js src/shell-post.js

Expand All @@ -70,19 +70,21 @@ EMFLAGS_PRE_JS_FILES = \

EXPORTED_METHODS_JSON_FILES = src/exported_functions.json src/exported_runtime_methods.json

FS_EXTERN_PATH = "$(realpath -s ./src/fs-externs.js)"

all: optimized debug worker

.PHONY: debug
debug: dist/sql-asm-debug.js dist/sql-wasm-debug.js

dist/sql-asm-debug.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES)
$(EMCC) $(EMFLAGS) $(EMFLAGS_DEBUG) $(EMFLAGS_ASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@
EMCC_CLOSURE_ARGS="--externs ${FS_EXTERN_PATH}" $(EMCC) $(EMFLAGS) $(EMFLAGS_DEBUG) $(EMFLAGS_ASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@
mv $@ out/tmp-raw.js
cat src/shell-pre.js out/tmp-raw.js src/shell-post.js > $@
rm out/tmp-raw.js

dist/sql-wasm-debug.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES)
$(EMCC) $(EMFLAGS) $(EMFLAGS_DEBUG) $(EMFLAGS_WASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@
EMCC_CLOSURE_ARGS="--externs ${FS_EXTERN_PATH}" $(EMCC) $(EMFLAGS) $(EMFLAGS_DEBUG) $(EMFLAGS_WASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@
mv $@ out/tmp-raw.js
cat src/shell-pre.js out/tmp-raw.js src/shell-post.js > $@
rm out/tmp-raw.js
Expand All @@ -91,19 +93,19 @@ dist/sql-wasm-debug.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FI
optimized: dist/sql-asm.js dist/sql-wasm.js dist/sql-asm-memory-growth.js

dist/sql-asm.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES)
$(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@
EMCC_CLOSURE_ARGS="--externs ${FS_EXTERN_PATH}" $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@
mv $@ out/tmp-raw.js
cat src/shell-pre.js out/tmp-raw.js src/shell-post.js > $@
rm out/tmp-raw.js

dist/sql-wasm.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES)
$(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_WASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@
EMCC_CLOSURE_ARGS="--externs ${FS_EXTERN_PATH}" $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_WASM) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@
mv $@ out/tmp-raw.js
cat src/shell-pre.js out/tmp-raw.js src/shell-post.js > $@
rm out/tmp-raw.js

dist/sql-asm-memory-growth.js: $(BITCODE_FILES) $(OUTPUT_WRAPPER_FILES) $(SOURCE_API_FILES) $(EXPORTED_METHODS_JSON_FILES)
$(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ASM_MEMORY_GROWTH) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@
EMCC_CLOSURE_ARGS="--externs ${FS_EXTERN_PATH}" $(EMCC) $(EMFLAGS) $(EMFLAGS_OPTIMIZED) $(EMFLAGS_ASM_MEMORY_GROWTH) $(BITCODE_FILES) $(EMFLAGS_PRE_JS_FILES) -o $@
mv $@ out/tmp-raw.js
cat src/shell-pre.js out/tmp-raw.js src/shell-post.js > $@
rm out/tmp-raw.js
Expand Down Expand Up @@ -153,6 +155,11 @@ out/extension-functions.o: sqlite-src/$(SQLITE_AMALGAMATION)
# Generate llvm bitcode
$(EMCC) $(SQLITE_COMPILATION_FLAGS) -c sqlite-src/$(SQLITE_AMALGAMATION)/extension-functions.c -o $@

out/vfs.o: src/vfs.c sqlite-src/$(SQLITE_AMALGAMATION)
mkdir -p out
# Generate object file
$(EMCC) $(CFLAGS) -I sqlite-src/$(SQLITE_AMALGAMATION) -c src/vfs.c -o $@

# TODO: This target appears to be unused. If we re-instatate it, we'll need to add more files inside of the JS folder
# module.tar.gz: test package.json AUTHORS README.md dist/sql-asm.js
# tar --create --gzip $^ > $@
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
> [!IMPORTANT]
> This is fork of the original sql.js library with extra bits and bobs from the fork of @jlongster/sql.js to enable absurd-sql support
> It is being used in Obsidian SQLSeal to enable latest SQLite version





<img src="https://user-images.githubusercontent.com/552629/76405509-87025300-6388-11ea-86c9-af882abb00bd.png" width="40" height="40" />

# SQLite compiled to JavaScript
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "sql.js",
"name": "@hypersphere/sql.js",
"version": "1.13.0",
"description": "SQLite library with support for opening and writing databases, prepared statements, and more. This SQLite library is in pure javascript (compiled with emscripten).",
"keywords": [
Expand Down
89 changes: 72 additions & 17 deletions src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -829,22 +829,30 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
* @memberof module:SqlJs
* Open a new database either by creating a new one or opening an existing
* one stored in the byte array passed in first argument
* @param {Array<number>} data An array of bytes representing
* an SQLite database file
* @param {Array<number>|string} data An array of bytes representing
* an SQLite database file or a path
* @param {Object} opts Options to specify a filename
*/
function Database(data) {
this.filename = "dbfile_" + (0xffffffff * Math.random() >>> 0);
if (data != null) {
FS.createDataFile("/", this.filename, data, true, true);
function Database(data, { filename = false } = {}) {
if(filename === false) {
this.filename = "dbfile_" + (0xffffffff * Math.random() >>> 0);
this.memoryFile = true; // Add this line to track if it's a memory file
if (data != null) {
FS.createDataFile("/", this.filename, data, true, true);
}
}
else {
this.filename = data;
}
this.handleError(sqlite3_open(this.filename, apiTemp));
this.db = getValue(apiTemp, "i32");
registerExtensionFunctions(this.db);
// A list of all prepared statements of the database
this.statements = {};
// A list of all user function of the database
// (created by create_function call)
// A list of custom functions registered by this database instance
this.functions = {};
// Callbacks for update hook
this.updateHookFunctionPtr = undefined;
}

/** Execute an SQL query, ignoring the rows it returns.
Expand Down Expand Up @@ -1115,23 +1123,25 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
* memory consumption will grow forever
*/
Database.prototype["close"] = function close() {
// do nothing if db is null or already closed
if (this.db === null) {
return;
}
Object.values(this.statements).forEach(function each(stmt) {
stmt["free"]();
if (!this.db) return;

Object.keys(this.statements).forEach((statementId) => {
this["run"](this.statements[statementId], ["--close"]);
});
Object.values(this.functions).forEach(removeFunction);
this.functions = {};

if (this.updateHookFunctionPtr) {
removeFunction(this.updateHookFunctionPtr);
this.updateHookFunctionPtr = undefined;
}

this.handleError(sqlite3_close_v2(this.db));
FS.unlink("/" + this.filename);

if(this.memoryFile) {
FS.unlink("/" + this.filename);
}

this.db = null;
};

Expand Down Expand Up @@ -1530,4 +1540,49 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {

// export Database to Module
Module.Database = Database;

// Because emscripten doesn't allow us to handle `ioctl`, we need
// to manually install lock/unlock methods. Unfortunately we need
// to keep track of a mapping of `sqlite_file*` pointers to filename
// so that we can tell our filesystem which files to lock/unlock
var sqliteFiles = new Map();

Module["register_for_idb"] = (customFS) => {
var SQLITE_BUSY = 5;

function open(namePtr, file) {
var path = UTF8ToString(namePtr);
sqliteFiles.set(file, path);
}

function lock(file, lockType) {
var path = sqliteFiles.get(file);
var success = customFS.lock(path, lockType)
return success? 0 : SQLITE_BUSY;
}

function unlock(file,lockType) {
var path = sqliteFiles.get(file);
customFS.unlock(path, lockType)
return 0;
}

let lockPtr = addFunction(lock, 'iii');
let unlockPtr = addFunction(unlock, 'iii');
let openPtr = addFunction(open, 'vii');
Module["_register_for_idb"](lockPtr, unlockPtr, openPtr)
}

// TODO: This isn't called from anywhere yet. We need to
// somehow cleanup closed files from `sqliteFiles`
Module["cleanup_file"] = (path) => {
let filesInfo = [...sqliteFiles.entries()]
let fileInfo = filesInfo.find(f => f[1] === path);
sqliteFiles.delete(fileInfo[0])
}

Module["reset_filesystem"] = () => {
FS.root = null;
FS.staticInit();
}
};
6 changes: 4 additions & 2 deletions src/exported_functions.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
"_sqlite3_result_int64",
"_sqlite3_result_error",
"_sqlite3_aggregate_context",
"_RegisterExtensionFunctions",
"_sqlite3_update_hook"
"_sqlite3_update_hook",
"_sqlite3_vfs_find",
"_register_for_idb",
"_RegisterExtensionFunctions"
]
4 changes: 2 additions & 2 deletions src/exported_runtime_methods.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
"stackSave",
"stackRestore",
"UTF8ToString",

"allocate",
"ALLOC_NORMAL",
"allocateUTF8OnStack",
"removeFunction",
"addFunction"
"addFunction",
"FS"
]
48 changes: 48 additions & 0 deletions src/fs-externs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* @externs
*/

Module.FS = class {
constructor() {
this.ErrnoError = class {};
}
mount() {}
isRoot() {}
isFile() {}
isDir() {}
stat() {}
/** @return {FSNode} */
lookupPath() {}
/** @return {FSNode} */
lookupNode() {}
/** @return {FSNode} */
createNode() {}
/** @return {FSNode} */
mknod() {}
};

Module.FS.FSNode = class {
constructor() {
this.node_ops = {
getattr: () => {},
setattr: () => {},
lookup: () => {},
mknod: () => {},
rename: () => {},
unlink: () => {},
rmdir: () => {},
reaaddir: () => {},
symlink: () => {},
readlink: () => {}
};

this.stream_ops = {
llseek: () => {},
read: () => {},
write: () => {},
allocate: () => {},
mmap: () => {},
msync: () => {}
};
}
};
47 changes: 47 additions & 0 deletions src/vfs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include <sqlite3.h>
#include <stdio.h>

static int (*defaultOpen)(sqlite3_vfs *vfs, const char *zName, sqlite3_file *file, int flags, int *pOutFlags);

static void (*fsOpen)(const char *, void*);
static int (*fsLock)(sqlite3_file *file, int);
static int (*fsUnlock)(sqlite3_file *file, int);

static int blockDeviceCharacteristics(sqlite3_file* file) {
return SQLITE_IOCAP_SAFE_APPEND |
SQLITE_IOCAP_SEQUENTIAL |
SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
}

static int block_lock(sqlite3_file *file, int lock) {
return fsLock(file, lock);
}

static int block_unlock(sqlite3_file *file, int lock) {
return fsUnlock(file, lock);
}

static int block_open(sqlite3_vfs *vfs, const char *zName, sqlite3_file *file, int flags, int *pOutFlags) {
int res = defaultOpen(vfs, zName, file, flags, pOutFlags);

sqlite3_io_methods* methods = (sqlite3_io_methods*)file->pMethods;
methods->xDeviceCharacteristics = blockDeviceCharacteristics;
methods->xLock = block_lock;
methods->xUnlock = block_unlock;

fsOpen(zName, (void*)file);

return res;
}

void register_for_idb(int(*lockFile)(sqlite3_file*,int), int(*unlockFile)(sqlite3_file*,int), void(*openFile)(const char*, void*)) {
sqlite3_vfs *vfs = sqlite3_vfs_find("unix");
defaultOpen = vfs->xOpen;

vfs->xOpen = block_open;
sqlite3_vfs_register(vfs, 1);

fsLock = lockFile;
fsUnlock = unlockFile;
fsOpen = openFile;
}