rtree-sql.js
Version:
SQLite library with support for opening and writing databases, prepared statements, and more. This SQLite library is in pure javascript (compiled with emscripten).
1,494 lines (1,201 loc) • 308 kB
JavaScript
// We are modularizing this manually because the current modularize setting in Emscripten has some issues:
// https://github.com/kripken/emscripten/issues/5820
// In addition, When you use emcc's modularization, it still expects to export a global object called `Module`,
// which is able to be used/called before the WASM is loaded.
// The modularization below exports a promise that loads and resolves to the actual sql.js module.
// That way, this module can't be used before the WASM is finished loading.
// We are going to define a function that a user will call to start loading initializing our Sql.js library
// However, that function might be called multiple times, and on subsequent calls, we don't actually want it to instantiate a new instance of the Module
// Instead, we want to return the previously loaded module
// TODO: Make this not declare a global if used in the browser
var initSqlJsPromise = undefined;
var initSqlJs = function (moduleConfig) {
if (initSqlJsPromise){
return initSqlJsPromise;
}
// If we're here, we've never called this function before
initSqlJsPromise = new Promise((resolveModule, reject) => {
// We are modularizing this manually because the current modularize setting in Emscripten has some issues:
// https://github.com/kripken/emscripten/issues/5820
// The way to affect the loading of emcc compiled modules is to create a variable called `Module` and add
// properties to it, like `preRun`, `postRun`, etc
// We are using that to get notified when the WASM has finished loading.
// Only then will we return our promise
// If they passed in a moduleConfig object, use that
// Otherwise, initialize Module to the empty object
var Module = typeof moduleConfig !== 'undefined' ? moduleConfig : {};
// EMCC only allows for a single onAbort function (not an array of functions)
// So if the user defined their own onAbort function, we remember it and call it
var originalOnAbortFunction = Module['onAbort'];
Module['onAbort'] = function (errorThatCausedAbort) {
reject(new Error(errorThatCausedAbort));
if (originalOnAbortFunction){
originalOnAbortFunction(errorThatCausedAbort);
}
};
Module['postRun'] = Module['postRun'] || [];
Module['postRun'].push(function () {
// When Emscripted calls postRun, this promise resolves with the built Module
resolveModule(Module);
});
// There is a section of code in the emcc-generated code below that looks like this:
// (Note that this is lowercase `module`)
// if (typeof module !== 'undefined') {
// module['exports'] = Module;
// }
// When that runs, it's going to overwrite our own modularization export efforts in shell-post.js!
// The only way to tell emcc not to emit it is to pass the MODULARIZE=1 or MODULARIZE_INSTANCE=1 flags,
// but that carries with it additional unnecessary baggage/bugs we don't want either.
// So, we have three options:
// 1) We undefine `module`
// 2) We remember what `module['exports']` was at the beginning of this function and we restore it later
// 3) We write a script to remove those lines of code as part of the Make process.
//
// Since those are the only lines of code that care about module, we will undefine it. It's the most straightforward
// of the options, and has the side effect of reducing emcc's efforts to modify the module if its output were to change in the future.
// That's a nice side effect since we're handling the modularization efforts ourselves
module = undefined;
// The emcc-generated code and shell-post.js code goes below,
// meaning that all of it runs inside of this promise. If anything throws an exception, our promise will abort
// Copyright 2010 The Emscripten Authors. All rights reserved.
// Emscripten is available under two separate licenses, the MIT license and the
// University of Illinois/NCSA Open Source License. Both these licenses can be
// found in the LICENSE file.
// The Module object: Our interface to the outside world. We import
// and export values on it. There are various ways Module can be used:
// 1. Not defined. We create it here
// 2. A function parameter, function(Module) { ..generated code.. }
// 3. pre-run appended it, var Module = {}; ..generated code..
// 4. External script tag defines var Module.
// We need to check if Module already exists (e.g. case 3 above).
// Substitution will be replaced with actual code on later stage of the build,
// this way Closure Compiler will not mangle it (e.g. case 4. above).
// Note that if you want to run closure, and also to use Module
// after the generated code, you will need to define var Module = {};
// before the code. Then that object will be used in the code, and you
// can continue to use Module afterwards as well.
var Module = typeof Module !== 'undefined' ? Module : {};
// --pre-jses are emitted after the Module integration code, so that they can
// refer to Module (if they choose; they can also define Module)
// Wait for preRun to run, and then finish our initialization
var runCompiledCode = (function() {// Generated by CoffeeScript 1.12.7
var Database, NULL, RegisterExtensionFunctions, SQLite, Statement, apiTemp, i, sqlite3_bind_blob, sqlite3_bind_double, sqlite3_bind_int, sqlite3_bind_parameter_index, sqlite3_bind_text, sqlite3_changes, sqlite3_clear_bindings, sqlite3_close_v2, sqlite3_column_blob, sqlite3_column_bytes, sqlite3_column_double, sqlite3_column_name, sqlite3_column_text, sqlite3_column_type, sqlite3_create_function_v2, sqlite3_data_count, sqlite3_errmsg, sqlite3_exec, sqlite3_finalize, sqlite3_free, sqlite3_open, sqlite3_prepare_v2, sqlite3_prepare_v2_sqlptr, sqlite3_reset, sqlite3_result_blob, sqlite3_result_double, sqlite3_result_error, sqlite3_result_int, sqlite3_result_int64, sqlite3_result_null, sqlite3_result_text, sqlite3_step, sqlite3_value_blob, sqlite3_value_bytes, sqlite3_value_double, sqlite3_value_int, sqlite3_value_text, sqlite3_value_type;
apiTemp = stackAlloc(4);
SQLite = {};
/* Represents a prepared statement.
Prepared statements allow you to have a template sql string,
that you can execute multiple times with different parameters.
You can't instantiate this class directly, you have to use a [Database](Database.html)
object in order to create a statement.
**Warning**: When you close a database (using db.close()), all its statements are
closed too and become unusable.
@see Database.html#prepare-dynamic
@see https://en.wikipedia.org/wiki/Prepared_statement
*/
Statement = (function() {
function Statement(stmt1, db) {
this.stmt = stmt1;
this.db = db;
this.pos = 1;
this.allocatedmem = [];
}
/* Bind values to the parameters, after having reseted the statement
SQL statements can have parameters, named *'?', '?NNN', ':VVV', '@VVV', '$VVV'*,
where NNN is a number and VVV a string.
This function binds these parameters to the given values.
*Warning*: ':', '@', and '$' are included in the parameters names
## Binding values to named parameters
@example Bind values to named parameters
var stmt = db.prepare("UPDATE test SET a=@newval WHERE id BETWEEN $mini AND $maxi");
stmt.bind({$mini:10, $maxi:20, '@newval':5});
- Create a statement that contains parameters like '$VVV', ':VVV', '@VVV'
- Call Statement.bind with an object as parameter
## Binding values to parameters
@example Bind values to anonymous parameters
var stmt = db.prepare("UPDATE test SET a=? WHERE id BETWEEN ? AND ?");
stmt.bind([5, 10, 20]);
- Create a statement that contains parameters like '?', '?NNN'
- Call Statement.bind with an array as parameter
## Value types
Javascript type | SQLite type
--- | ---
number | REAL, INTEGER
boolean | INTEGER
string | TEXT
Array, Uint8Array | BLOB
null | NULL
@see http://www.sqlite.org/datatype3.html
@see http://www.sqlite.org/lang_expr.html#varparam
@param values [Array,Object] The values to bind
@return [Boolean] true if it worked
@throw [String] SQLite Error
*/
Statement.prototype['bind'] = function(values) {
if (!this.stmt) {
throw "Statement closed";
}
this['reset']();
if (Array.isArray(values)) {
return this.bindFromArray(values);
} else {
return this.bindFromObject(values);
}
};
/* Execute the statement, fetching the the next line of result,
that can be retrieved with [Statement.get()](#get-dynamic) .
@return [Boolean] true if a row of result available
@throw [String] SQLite Error
*/
Statement.prototype['step'] = function() {
var ret;
if (!this.stmt) {
throw "Statement closed";
}
this.pos = 1;
switch (ret = sqlite3_step(this.stmt)) {
case SQLite.ROW:
return true;
case SQLite.DONE:
return false;
default:
return this.db.handleError(ret);
}
};
Statement.prototype.getNumber = function(pos) {
if (pos == null) {
pos = this.pos++;
}
return sqlite3_column_double(this.stmt, pos);
};
Statement.prototype.getString = function(pos) {
if (pos == null) {
pos = this.pos++;
}
return sqlite3_column_text(this.stmt, pos);
};
Statement.prototype.getBlob = function(pos) {
var i, k, ptr, ref, result, size;
if (pos == null) {
pos = this.pos++;
}
size = sqlite3_column_bytes(this.stmt, pos);
ptr = sqlite3_column_blob(this.stmt, pos);
result = new Uint8Array(size);
for (i = k = 0, ref = size; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) {
result[i] = HEAP8[ptr + i];
}
return result;
};
/* Get one row of results of a statement.
If the first parameter is not provided, step must have been called before get.
@param [Array,Object] Optional: If set, the values will be bound to the statement, and it will be executed
@return [Array<String,Number,Uint8Array,null>] One row of result
@example Print all the rows of the table test to the console
var stmt = db.prepare("SELECT * FROM test");
while (stmt.step()) console.log(stmt.get());
*/
Statement.prototype['get'] = function(params) {
var field, k, ref, results1;
if (params != null) {
this['bind'](params) && this['step']();
}
results1 = [];
for (field = k = 0, ref = sqlite3_data_count(this.stmt); 0 <= ref ? k < ref : k > ref; field = 0 <= ref ? ++k : --k) {
switch (sqlite3_column_type(this.stmt, field)) {
case SQLite.INTEGER:
case SQLite.FLOAT:
results1.push(this.getNumber(field));
break;
case SQLite.TEXT:
results1.push(this.getString(field));
break;
case SQLite.BLOB:
results1.push(this.getBlob(field));
break;
default:
results1.push(null);
}
}
return results1;
};
/* Get the list of column names of a row of result of a statement.
@return [Array<String>] The names of the columns
@example
var stmt = db.prepare("SELECT 5 AS nbr, x'616200' AS data, NULL AS null_value;");
stmt.step(); // Execute the statement
console.log(stmt.getColumnNames()); // Will print ['nbr','data','null_value']
*/
Statement.prototype['getColumnNames'] = function() {
var i, k, ref, results1;
results1 = [];
for (i = k = 0, ref = sqlite3_data_count(this.stmt); 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) {
results1.push(sqlite3_column_name(this.stmt, i));
}
return results1;
};
/* Get one row of result as a javascript object, associating column names with
their value in the current row.
@param [Array,Object] Optional: If set, the values will be bound to the statement, and it will be executed
@return [Object] The row of result
@see [Statement.get](#get-dynamic)
@example
var stmt = db.prepare("SELECT 5 AS nbr, x'616200' AS data, NULL AS null_value;");
stmt.step(); // Execute the statement
console.log(stmt.getAsObject()); // Will print {nbr:5, data: Uint8Array([1,2,3]), null_value:null}
*/
Statement.prototype['getAsObject'] = function(params) {
var i, k, len, name, names, rowObject, values;
values = this['get'](params);
names = this['getColumnNames']();
rowObject = {};
for (i = k = 0, len = names.length; k < len; i = ++k) {
name = names[i];
rowObject[name] = values[i];
}
return rowObject;
};
/* Shorthand for bind + step + reset
Bind the values, execute the statement, ignoring the rows it returns, and resets it
@param [Array,Object] Value to bind to the statement
*/
Statement.prototype['run'] = function(values) {
if (values != null) {
this['bind'](values);
}
this['step']();
return this['reset']();
};
Statement.prototype.bindString = function(string, pos) {
var bytes, strptr;
if (pos == null) {
pos = this.pos++;
}
bytes = intArrayFromString(string);
this.allocatedmem.push(strptr = allocate(bytes, 'i8', ALLOC_NORMAL));
this.db.handleError(sqlite3_bind_text(this.stmt, pos, strptr, bytes.length - 1, 0));
return true;
};
Statement.prototype.bindBlob = function(array, pos) {
var blobptr;
if (pos == null) {
pos = this.pos++;
}
this.allocatedmem.push(blobptr = allocate(array, 'i8', ALLOC_NORMAL));
this.db.handleError(sqlite3_bind_blob(this.stmt, pos, blobptr, array.length, 0));
return true;
};
Statement.prototype.bindNumber = function(num, pos) {
var bindfunc;
if (pos == null) {
pos = this.pos++;
}
bindfunc = num === (num | 0) ? sqlite3_bind_int : sqlite3_bind_double;
this.db.handleError(bindfunc(this.stmt, pos, num));
return true;
};
Statement.prototype.bindNull = function(pos) {
if (pos == null) {
pos = this.pos++;
}
return sqlite3_bind_blob(this.stmt, pos, 0, 0, 0) === SQLite.OK;
};
Statement.prototype.bindValue = function(val, pos) {
if (pos == null) {
pos = this.pos++;
}
switch (typeof val) {
case "string":
return this.bindString(val, pos);
case "number":
case "boolean":
return this.bindNumber(val + 0, pos);
case "object":
if (val === null) {
return this.bindNull(pos);
} else if (val.length != null) {
return this.bindBlob(val, pos);
} else {
throw "Wrong API use : tried to bind a value of an unknown type (" + val + ").";
}
}
};
/* Bind names and values of an object to the named parameters of the statement
@param [Object]
@private
@nodoc
*/
Statement.prototype.bindFromObject = function(valuesObj) {
var name, num, value;
for (name in valuesObj) {
value = valuesObj[name];
num = sqlite3_bind_parameter_index(this.stmt, name);
if (num !== 0) {
this.bindValue(value, num);
}
}
return true;
};
/* Bind values to numbered parameters
@param [Array]
@private
@nodoc
*/
Statement.prototype.bindFromArray = function(values) {
var k, len, num, value;
for (num = k = 0, len = values.length; k < len; num = ++k) {
value = values[num];
this.bindValue(value, num + 1);
}
return true;
};
/* Reset a statement, so that it's parameters can be bound to new values
It also clears all previous bindings, freeing the memory used by bound parameters.
*/
Statement.prototype['reset'] = function() {
this.freemem();
return sqlite3_clear_bindings(this.stmt) === SQLite.OK && sqlite3_reset(this.stmt) === SQLite.OK;
};
/* Free the memory allocated during parameter binding
*/
Statement.prototype.freemem = function() {
var mem;
while (mem = this.allocatedmem.pop()) {
_free(mem);
}
return null;
};
/* Free the memory used by the statement
@return [Boolean] true in case of success
*/
Statement.prototype['free'] = function() {
var res;
this.freemem();
res = sqlite3_finalize(this.stmt) === SQLite.OK;
delete this.db.statements[this.stmt];
this.stmt = NULL;
return res;
};
return Statement;
})();
Database = (function() {
function Database(data) {
this.filename = 'dbfile_' + (0xffffffff * Math.random() >>> 0);
if (data != null) {
FS.createDataFile('/', this.filename, data, true, true);
}
this.handleError(sqlite3_open(this.filename, apiTemp));
this.db = getValue(apiTemp, 'i32');
RegisterExtensionFunctions(this.db);
this.statements = {};
this.functions = {};
}
/* Execute an SQL query, ignoring the rows it returns.
@param sql [String] a string containing some SQL text to execute
@param params [Array] (*optional*) When the SQL statement contains placeholders, you can pass them in here. They will be bound to the statement before it is executed.
If you use the params argument, you **cannot** provide an sql string that contains several
queries (separated by ';')
@example Insert values in a table
db.run("INSERT INTO test VALUES (:age, :name)", {':age':18, ':name':'John'});
@return [Database] The database object (useful for method chaining)
*/
Database.prototype['run'] = function(sql, params) {
var stmt;
if (!this.db) {
throw "Database closed";
}
if (params) {
stmt = this['prepare'](sql, params);
try {
stmt['step']();
} finally {
stmt['free']();
}
} else {
this.handleError(sqlite3_exec(this.db, sql, 0, 0, apiTemp));
}
return this;
};
/* Execute an SQL query, and returns the result.
This is a wrapper against Database.prepare, Statement.step, Statement.get,
and Statement.free.
The result is an array of result elements. There are as many result elements
as the number of statements in your sql string (statements are separated by a semicolon)
Each result element is an object with two properties:
'columns' : the name of the columns of the result (as returned by Statement.getColumnNames())
'values' : an array of rows. Each row is itself an array of values
## Example use
We have the following table, named *test* :
| id | age | name |
|:--:|:---:|:------:|
| 1 | 1 | Ling |
| 2 | 18 | Paul |
| 3 | 3 | Markus |
We query it like that:
```javascript
var db = new SQL.Database();
var res = db.exec("SELECT id FROM test; SELECT age,name FROM test;");
```
`res` is now :
```javascript
[
{columns: ['id'], values:[[1],[2],[3]]},
{columns: ['age','name'], values:[[1,'Ling'],[18,'Paul'],[3,'Markus']]}
]
```
@param sql [String] a string containing some SQL text to execute
@return [Array<QueryResults>] An array of results.
*/
Database.prototype['exec'] = function(sql) {
var curresult, nextSqlPtr, pStmt, pzTail, results, stack, stmt;
if (!this.db) {
throw "Database closed";
}
stack = stackSave();
try {
nextSqlPtr = allocateUTF8OnStack(sql);
pzTail = stackAlloc(4);
results = [];
while (getValue(nextSqlPtr, 'i8') !== NULL) {
setValue(apiTemp, 0, 'i32');
setValue(pzTail, 0, 'i32');
this.handleError(sqlite3_prepare_v2_sqlptr(this.db, nextSqlPtr, -1, apiTemp, pzTail));
pStmt = getValue(apiTemp, 'i32');
nextSqlPtr = getValue(pzTail, 'i32');
if (pStmt === NULL) {
continue;
}
curresult = null;
stmt = new Statement(pStmt, this);
try {
while (stmt['step']()) {
if (curresult === null) {
curresult = {
'columns': stmt['getColumnNames'](),
'values': []
};
results.push(curresult);
}
curresult['values'].push(stmt['get']());
}
} finally {
stmt['free']();
}
}
return results;
} finally {
stackRestore(stack);
}
};
/* Execute an sql statement, and call a callback for each row of result.
**Currently** this method is synchronous, it will not return until the callback has
been called on every row of the result. But this might change.
@param sql [String] A string of SQL text. Can contain placeholders that will be
bound to the parameters given as the second argument
@param params [Array<String,Number,null,Uint8Array>] (*optional*) Parameters to bind
to the query
@param callback [Function(Object)] A function that will be called on each row of result
@param done [Function] A function that will be called when all rows have been retrieved
@return [Database] The database object. Useful for method chaining
@example Read values from a table
db.each("SELECT name,age FROM users WHERE age >= $majority",
{$majority:18},
function(row){console.log(row.name + " is a grown-up.")}
);
*/
Database.prototype['each'] = function(sql, params, callback, done) {
var stmt;
if (typeof params === 'function') {
done = callback;
callback = params;
params = void 0;
}
stmt = this['prepare'](sql, params);
try {
while (stmt['step']()) {
callback(stmt['getAsObject']());
}
} finally {
stmt['free']();
}
if (typeof done === 'function') {
return done();
}
};
/* Prepare an SQL statement
@param sql [String] a string of SQL, that can contain placeholders ('?', ':VVV', ':AAA', '@AAA')
@param params [Array] (*optional*) values to bind to placeholders
@return [Statement] the resulting statement
@throw [String] SQLite error
*/
Database.prototype['prepare'] = function(sql, params) {
var pStmt, stmt;
setValue(apiTemp, 0, 'i32');
this.handleError(sqlite3_prepare_v2(this.db, sql, -1, apiTemp, NULL));
pStmt = getValue(apiTemp, 'i32');
if (pStmt === NULL) {
throw 'Nothing to prepare';
}
stmt = new Statement(pStmt, this);
if (params != null) {
stmt.bind(params);
}
this.statements[pStmt] = stmt;
return stmt;
};
/* Exports the contents of the database to a binary array
@return [Uint8Array] An array of bytes of the SQLite3 database file
*/
Database.prototype['export'] = function() {
var _, binaryDb, func, ref, ref1, stmt;
ref = this.statements;
for (_ in ref) {
stmt = ref[_];
stmt['free']();
}
ref1 = this.functions;
for (_ in ref1) {
func = ref1[_];
removeFunction(func);
}
this.functions = {};
this.handleError(sqlite3_close_v2(this.db));
binaryDb = FS.readFile(this.filename, {
encoding: 'binary'
});
this.handleError(sqlite3_open(this.filename, apiTemp));
this.db = getValue(apiTemp, 'i32');
return binaryDb;
};
/* Close the database, and all associated prepared statements.
The memory associated to the database and all associated statements
will be freed.
**Warning**: A statement belonging to a database that has been closed cannot
be used anymore.
Databases **must** be closed, when you're finished with them, or the
memory consumption will grow forever
*/
Database.prototype['close'] = function() {
var _, func, ref, ref1, stmt;
ref = this.statements;
for (_ in ref) {
stmt = ref[_];
stmt['free']();
}
ref1 = this.functions;
for (_ in ref1) {
func = ref1[_];
removeFunction(func);
}
this.functions = {};
this.handleError(sqlite3_close_v2(this.db));
FS.unlink('/' + this.filename);
return this.db = null;
};
/* Analyze a result code, return null if no error occured, and throw
an error with a descriptive message otherwise
@nodoc
*/
Database.prototype.handleError = function(returnCode) {
var errmsg;
if (returnCode === SQLite.OK) {
return null;
} else {
errmsg = sqlite3_errmsg(this.db);
throw new Error(errmsg);
}
};
/* Returns the number of rows modified, inserted or deleted by the
most recently completed INSERT, UPDATE or DELETE statement on the
database Executing any other type of SQL statement does not modify
the value returned by this function.
@return [Number] the number of rows modified
*/
Database.prototype['getRowsModified'] = function() {
return sqlite3_changes(this.db);
};
/* Register a custom function with SQLite
@example Register a simple function
db.create_function("addOne", function(x) {return x+1;})
db.exec("SELECT addOne(1)") // = 2
@param name [String] the name of the function as referenced in SQL statements.
@param func [Function] the actual function to be executed.
*/
Database.prototype['create_function'] = function(name, func) {
var func_ptr, wrapped_func;
wrapped_func = function(cx, argc, argv) {
var arg, args, blobptr, data_func, error, i, k, ref, result, value_ptr, value_type;
args = [];
for (i = k = 0, ref = argc; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) {
value_ptr = getValue(argv + (4 * i), 'i32');
value_type = sqlite3_value_type(value_ptr);
data_func = (function() {
switch (false) {
case value_type !== 1:
return sqlite3_value_double;
case value_type !== 2:
return sqlite3_value_double;
case value_type !== 3:
return sqlite3_value_text;
case value_type !== 4:
return function(ptr) {
var blob_arg, blob_ptr, j, l, ref1, size;
size = sqlite3_value_bytes(ptr);
blob_ptr = sqlite3_value_blob(ptr);
blob_arg = new Uint8Array(size);
for (j = l = 0, ref1 = size; 0 <= ref1 ? l < ref1 : l > ref1; j = 0 <= ref1 ? ++l : --l) {
blob_arg[j] = HEAP8[blob_ptr + j];
}
return blob_arg;
};
default:
return function(ptr) {
return null;
};
}
})();
arg = data_func(value_ptr);
args.push(arg);
}
try {
result = func.apply(null, args);
} catch (error1) {
error = error1;
sqlite3_result_error(cx, error, -1);
return;
}
switch (typeof result) {
case 'boolean':
sqlite3_result_int(cx, result ? 1 : 0);
break;
case 'number':
sqlite3_result_double(cx, result);
break;
case 'string':
sqlite3_result_text(cx, result, -1, -1);
break;
case 'object':
if (result === null) {
sqlite3_result_null(cx);
} else if (result.length != null) {
blobptr = allocate(result, 'i8', ALLOC_NORMAL);
sqlite3_result_blob(cx, blobptr, result.length, -1);
_free(blobptr);
} else {
sqlite3_result_error(cx, "Wrong API use : tried to return a value of an unknown type (" + result + ").", -1);
}
break;
default:
sqlite3_result_null(cx);
}
};
if (name in this.functions) {
removeFunction(this.functions[name]);
delete this.functions[name];
}
func_ptr = addFunction(wrapped_func);
this.functions[name] = func_ptr;
this.handleError(sqlite3_create_function_v2(this.db, name, func.length, SQLite.UTF8, 0, func_ptr, 0, 0, 0));
return this;
};
return Database;
})();
sqlite3_open = Module['cwrap']('sqlite3_open', 'number', ['string', 'number']);
sqlite3_close_v2 = Module['cwrap']('sqlite3_close_v2', 'number', ['number']);
sqlite3_exec = Module['cwrap']('sqlite3_exec', 'number', ['number', 'string', 'number', 'number', 'number']);
sqlite3_free = Module['cwrap']('sqlite3_free', '', ['number']);
sqlite3_changes = Module['cwrap']('sqlite3_changes', 'number', ['number']);
sqlite3_prepare_v2 = Module['cwrap']('sqlite3_prepare_v2', 'number', ['number', 'string', 'number', 'number', 'number']);
sqlite3_prepare_v2_sqlptr = Module['cwrap']('sqlite3_prepare_v2', 'number', ['number', 'number', 'number', 'number', 'number']);
sqlite3_bind_text = Module['cwrap']('sqlite3_bind_text', 'number', ['number', 'number', 'number', 'number', 'number']);
sqlite3_bind_blob = Module['cwrap']('sqlite3_bind_blob', 'number', ['number', 'number', 'number', 'number', 'number']);
sqlite3_bind_double = Module['cwrap']('sqlite3_bind_double', 'number', ['number', 'number', 'number']);
sqlite3_bind_int = Module['cwrap']('sqlite3_bind_int', 'number', ['number', 'number', 'number']);
sqlite3_bind_parameter_index = Module['cwrap']('sqlite3_bind_parameter_index', 'number', ['number', 'string']);
sqlite3_step = Module['cwrap']('sqlite3_step', 'number', ['number']);
sqlite3_errmsg = Module['cwrap']('sqlite3_errmsg', 'string', ['number']);
sqlite3_data_count = Module['cwrap']('sqlite3_data_count', 'number', ['number']);
sqlite3_column_double = Module['cwrap']('sqlite3_column_double', 'number', ['number', 'number']);
sqlite3_column_text = Module['cwrap']('sqlite3_column_text', 'string', ['number', 'number']);
sqlite3_column_blob = Module['cwrap']('sqlite3_column_blob', 'number', ['number', 'number']);
sqlite3_column_bytes = Module['cwrap']('sqlite3_column_bytes', 'number', ['number', 'number']);
sqlite3_column_type = Module['cwrap']('sqlite3_column_type', 'number', ['number', 'number']);
sqlite3_column_name = Module['cwrap']('sqlite3_column_name', 'string', ['number', 'number']);
sqlite3_reset = Module['cwrap']('sqlite3_reset', 'number', ['number']);
sqlite3_clear_bindings = Module['cwrap']('sqlite3_clear_bindings', 'number', ['number']);
sqlite3_finalize = Module['cwrap']('sqlite3_finalize', 'number', ['number']);
sqlite3_create_function_v2 = Module['cwrap']('sqlite3_create_function_v2', 'number', ['number', 'string', 'number', 'number', 'number', 'number', 'number', 'number', 'number']);
sqlite3_value_type = Module['cwrap']('sqlite3_value_type', 'number', ['number']);
sqlite3_value_bytes = Module['cwrap']('sqlite3_value_bytes', 'number', ['number']);
sqlite3_value_text = Module['cwrap']('sqlite3_value_text', 'string', ['number']);
sqlite3_value_int = Module['cwrap']('sqlite3_value_int', 'number', ['number']);
sqlite3_value_blob = Module['cwrap']('sqlite3_value_blob', 'number', ['number']);
sqlite3_value_double = Module['cwrap']('sqlite3_value_double', 'number', ['number']);
sqlite3_result_double = Module['cwrap']('sqlite3_result_double', '', ['number', 'number']);
sqlite3_result_null = Module['cwrap']('sqlite3_result_null', '', ['number']);
sqlite3_result_text = Module['cwrap']('sqlite3_result_text', '', ['number', 'string', 'number', 'number']);
sqlite3_result_blob = Module['cwrap']('sqlite3_result_blob', '', ['number', 'number', 'number', 'number']);
sqlite3_result_int = Module['cwrap']('sqlite3_result_int', '', ['number', 'number']);
sqlite3_result_int64 = Module['cwrap']('sqlite3_result_int64', '', ['number', 'number']);
sqlite3_result_error = Module['cwrap']('sqlite3_result_error', '', ['number', 'string', 'number']);
RegisterExtensionFunctions = Module['cwrap']('RegisterExtensionFunctions', 'number', ['number']);
this['SQL'] = {
'Database': Database
};
for (i in this['SQL']) {
Module[i] = this['SQL'][i];
}
NULL = 0;
SQLite.OK = 0;
SQLite.ERROR = 1;
SQLite.INTERNAL = 2;
SQLite.PERM = 3;
SQLite.ABORT = 4;
SQLite.BUSY = 5;
SQLite.LOCKED = 6;
SQLite.NOMEM = 7;
SQLite.READONLY = 8;
SQLite.INTERRUPT = 9;
SQLite.IOERR = 10;
SQLite.CORRUPT = 11;
SQLite.NOTFOUND = 12;
SQLite.FULL = 13;
SQLite.CANTOPEN = 14;
SQLite.PROTOCOL = 15;
SQLite.EMPTY = 16;
SQLite.SCHEMA = 17;
SQLite.TOOBIG = 18;
SQLite.CONSTRAINT = 19;
SQLite.MISMATCH = 20;
SQLite.MISUSE = 21;
SQLite.NOLFS = 22;
SQLite.AUTH = 23;
SQLite.FORMAT = 24;
SQLite.RANGE = 25;
SQLite.NOTADB = 26;
SQLite.NOTICE = 27;
SQLite.WARNING = 28;
SQLite.ROW = 100;
SQLite.DONE = 101;
SQLite.INTEGER = 1;
SQLite.FLOAT = 2;
SQLite.TEXT = 3;
SQLite.BLOB = 4;
SQLite.NULL = 5;
SQLite.UTF8 = 1;
}).bind(this);
Module['onRuntimeInitialized'] = runCompiledCode;
// Sometimes an existing Module object exists with properties
// meant to overwrite the default module functionality. Here
// we collect those properties and reapply _after_ we configure
// the current environment's defaults to avoid having to be so
// defensive during initialization.
var moduleOverrides = {};
var key;
for (key in Module) {
if (Module.hasOwnProperty(key)) {
moduleOverrides[key] = Module[key];
}
}
var arguments_ = [];
var thisProgram = './this.program';
var quit_ = function(status, toThrow) {
throw toThrow;
};
// Determine the runtime environment we are in. You can customize this by
// setting the ENVIRONMENT setting at compile time (see settings.js).
var ENVIRONMENT_IS_WEB = false;
var ENVIRONMENT_IS_WORKER = false;
var ENVIRONMENT_IS_NODE = false;
var ENVIRONMENT_HAS_NODE = false;
var ENVIRONMENT_IS_SHELL = false;
ENVIRONMENT_IS_WEB = typeof window === 'object';
ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
// A web environment like Electron.js can have Node enabled, so we must
// distinguish between Node-enabled environments and Node environments per se.
// This will allow the former to do things like mount NODEFS.
// Extended check using process.versions fixes issue #8816.
// (Also makes redundant the original check that 'require' is a function.)
ENVIRONMENT_HAS_NODE = typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string';
ENVIRONMENT_IS_NODE = ENVIRONMENT_HAS_NODE && !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_WORKER;
ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
if (Module['ENVIRONMENT']) {
throw new Error('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -s ENVIRONMENT=web or -s ENVIRONMENT=node)');
}
// Three configurations we can be running in:
// 1) We could be the application main() thread running in the main JS UI thread. (ENVIRONMENT_IS_WORKER == false and ENVIRONMENT_IS_PTHREAD == false)
// 2) We could be the application main() thread proxied to worker. (with Emscripten -s PROXY_TO_WORKER=1) (ENVIRONMENT_IS_WORKER == true, ENVIRONMENT_IS_PTHREAD == false)
// 3) We could be an application pthread running in a worker. (ENVIRONMENT_IS_WORKER == true and ENVIRONMENT_IS_PTHREAD == true)
// `/` should be present at the end if `scriptDirectory` is not empty
var scriptDirectory = '';
function locateFile(path) {
if (Module['locateFile']) {
return Module['locateFile'](path, scriptDirectory);
}
return scriptDirectory + path;
}
// Hooks that are implemented differently in different runtime environments.
var read_,
readAsync,
readBinary,
setWindowTitle;
if (ENVIRONMENT_IS_NODE) {
scriptDirectory = __dirname + '/';
// Expose functionality in the same simple way that the shells work
// Note that we pollute the global namespace here, otherwise we break in node
var nodeFS;
var nodePath;
read_ = function shell_read(filename, binary) {
var ret;
if (!nodeFS) nodeFS = require('fs');
if (!nodePath) nodePath = require('path');
filename = nodePath['normalize'](filename);
ret = nodeFS['readFileSync'](filename);
return binary ? ret : ret.toString();
};
readBinary = function readBinary(filename) {
var ret = read_(filename, true);
if (!ret.buffer) {
ret = new Uint8Array(ret);
}
assert(ret.buffer);
return ret;
};
if (process['argv'].length > 1) {
thisProgram = process['argv'][1].replace(/\\/g, '/');
}
arguments_ = process['argv'].slice(2);
if (typeof module !== 'undefined') {
module['exports'] = Module;
}
process['on']('unhandledRejection', abort);
quit_ = function(status) {
process['exit'](status);
};
Module['inspect'] = function () { return '[Emscripten Module object]'; };
} else
if (ENVIRONMENT_IS_SHELL) {
if (typeof read != 'undefined') {
read_ = function shell_read(f) {
return read(f);
};
}
readBinary = function readBinary(f) {
var data;
if (typeof readbuffer === 'function') {
return new Uint8Array(readbuffer(f));
}
data = read(f, 'binary');
assert(typeof data === 'object');
return data;
};
if (typeof scriptArgs != 'undefined') {
arguments_ = scriptArgs;
} else if (typeof arguments != 'undefined') {
arguments_ = arguments;
}
if (typeof quit === 'function') {
quit_ = function(status) {
quit(status);
};
}
if (typeof print !== 'undefined') {
// Prefer to use print/printErr where they exist, as they usually work better.
if (typeof console === 'undefined') console = {};
console.log = print;
console.warn = console.error = typeof printErr !== 'undefined' ? printErr : print;
}
} else
if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
if (ENVIRONMENT_IS_WORKER) { // Check worker, not web, since window could be polyfilled
scriptDirectory = self.location.href;
} else if (document.currentScript) { // web
scriptDirectory = document.currentScript.src;
}
// blob urls look like blob:http://site.com/etc/etc and we cannot infer anything from them.
// otherwise, slice off the final part of the url to find the script directory.
// if scriptDirectory does not contain a slash, lastIndexOf will return -1,
// and scriptDirectory will correctly be replaced with an empty string.
if (scriptDirectory.indexOf('blob:') !== 0) {
scriptDirectory = scriptDirectory.substr(0, scriptDirectory.lastIndexOf('/')+1);
} else {
scriptDirectory = '';
}
read_ = function shell_read(url) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.send(null);
return xhr.responseText;
};
if (ENVIRONMENT_IS_WORKER) {
readBinary = function readBinary(url) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
xhr.responseType = 'arraybuffer';
xhr.send(null);
return new Uint8Array(xhr.response);
};
}
readAsync = function readAsync(url, onload, onerror) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function xhr_onload() {
if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
onload(xhr.response);
return;
}
onerror();
};
xhr.onerror = onerror;
xhr.send(null);
};
setWindowTitle = function(title) { document.title = title };
} else
{
throw new Error('environment detection error');
}
// Set up the out() and err() hooks, which are how we can print to stdout or
// stderr, respectively.
var out = Module['print'] || console.log.bind(console);
var err = Module['printErr'] || console.warn.bind(console);
// Merge back in the overrides
for (key in moduleOverrides) {
if (moduleOverrides.hasOwnProperty(key)) {
Module[key] = moduleOverrides[key];
}
}
// Free the object hierarchy contained in the overrides, this lets the GC
// reclaim data used e.g. in memoryInitializerRequest, which is a large typed array.
moduleOverrides = null;
// Emit code to handle expected values on the Module object. This applies Module.x
// to the proper local x. This has two benefits: first, we only emit it if it is
// expected to arrive, and second, by using a local everywhere else that can be
// minified.
if (Module['arguments']) arguments_ = Module['arguments'];if (!Object.getOwnPropertyDescriptor(Module, 'arguments')) Object.defineProperty(Module, 'arguments', { get: function() { abort('Module.arguments has been replaced with plain arguments_') } });
if (Module['thisProgram']) thisProgram = Module['thisProgram'];if (!Object.getOwnPropertyDescriptor(Module, 'thisProgram')) Object.defineProperty(Module, 'thisProgram', { get: function() { abort('Module.thisProgram has been replaced with plain thisProgram') } });
if (Module['quit']) quit_ = Module['quit'];if (!Object.getOwnPropertyDescriptor(Module, 'quit')) Object.defineProperty(Module, 'quit', { get: function() { abort('Module.quit has been replaced with plain quit_') } });
// perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message
// Assertions on removed incoming Module JS APIs.
assert(typeof Module['memoryInitializerPrefixURL'] === 'undefined', 'Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead');
assert(typeof Module['pthreadMainPrefixURL'] === 'undefined', 'Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead');
assert(typeof Module['cdInitializerPrefixURL'] === 'undefined', 'Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead');
assert(typeof Module['filePackagePrefixURL'] === 'undefined', 'Module.filePackagePrefixURL option was removed, use Module.locateFile instead');
assert(typeof Module['read'] === 'undefined', 'Module.read option was removed (modify read_ in JS)');
assert(typeof Module['readAsync'] === 'undefined', 'Module.readAsync option was removed (modify readAsync in JS)');
assert(typeof Module['readBinary'] === 'undefined', 'Module.readBinary option was removed (modify readBinary in JS)');
assert(typeof Module['setWindowTitle'] === 'undefined', 'Module.setWindowTitle option was removed (modify setWindowTitle in JS)');
if (!Object.getOwnPropertyDescriptor(Module, 'read')) Object.defineProperty(Module, 'read', { get: function() { abort('Module.read has been replaced with plain read_') } });
if (!Object.getOwnPropertyDescriptor(Module, 'readAsync')) Object.defineProperty(Module, 'readAsync', { get: function() { abort('Module.readAsync has been replaced with plain readAsync') } });
if (!Object.getOwnPropertyDescriptor(Module, 'readBinary')) Object.defineProperty(Module, 'readBinary', { get: function() { abort('Module.readBinary has been replaced with plain readBinary') } });
// TODO: add when SDL2 is fixed if (!Object.getOwnPropertyDescriptor(Module, 'setWindowTitle')) Object.defineProperty(Module, 'setWindowTitle', { get: function() { abort('Module.setWindowTitle has been replaced with plain setWindowTitle') } });
// TODO remove when SDL2 is fixed (also see above)
// Copyright 2017 The Emscripten Authors. All rights reserved.
// Emscripten is available under two separate licenses, the MIT license and the
// University of Illinois/NCSA Open Source License. Both these licenses can be
// found in the LICENSE file.
// {{PREAMBLE_ADDITIONS}}
var STACK_ALIGN = 16;
// stack management, and other functionality that is provided by the compiled code,
// should not be used before it is ready
stackSave = stackRestore = stackAlloc = function() {
abort('cannot use the stack before compiled code is ready to run, and has provided stack access');
};
function staticAlloc(size) {
abort('staticAlloc is no longer available at runtime; instead, perform static allocations at compile time (using makeStaticAlloc)');
}
function dynamicAlloc(size) {
assert(DYNAMICTOP_PTR);
var ret = HEAP32[DYNAMICTOP_PTR>>2];
var end = (ret + size + 15) & -16;
if (end > _emscripten_get_heap_size()) {
abort('failure to dynamicAlloc - memory growth etc. is not supported there, call malloc/sbrk directly');
}
HEAP32[DYNAMICTOP_PTR>>2] = end;
return ret;
}
function alignMemory(size, factor) {
if (!factor) factor = STACK_ALIGN; // stack alignment (16-byte) by default
return Math.ceil(size / factor) * factor;
}
function getNativeTypeSize(type) {
switch (type) {
case 'i1': case 'i8': return 1;
case 'i16': return 2;
case 'i32': return 4;
case 'i64': return 8;
case 'float': return 4;
case 'double': return 8;
default: {
if (type[type.length-1] === '*') {
return 4; // A pointer
} else if (type[0] === 'i') {
var bits = parseInt(type.substr(1));
assert(bits % 8 === 0, 'getNativeTypeSize invalid bits ' + bits + ', type ' + type);
return bits / 8;
} else {
return 0;
}
}
}
}
function warnOnce(text) {
if (!warnOnce.shown) warnOnce.shown = {};
if (!warnOnce.shown[text]) {
warnOnce.shown[text] = 1;
err(text);
}
}
var asm2wasmImports = { // special asm2wasm imports
"f64-rem": function(x, y) {
return x % y;
},
"debugger": function() {
debugger;
}
};
var jsCallStartIndex = 1;
var functionPointers = new Array(64);
// Wraps a JS function as a wasm function with a given signature.
// In the future, we may get a WebAssembly.Function constructor. Until then,
// we create a wasm module that takes the JS function as an import with a given
// signature, and re-exports that as a wasm function.
function convertJsFunctionToWasm(func, sig) {
// The module is static, with the exception of the type section, which is
// generated based on the signature passed in.
var typeSection = [
0x01, // id: section,
0x00, // length: 0 (placeholder)
0x01, // count: 1
0x60, // form: func
];
var sigRet = sig.slice(0, 1);
var sigParam = sig.slice(1);
var typeCodes = {
'i': 0x7f, // i32
'j': 0x7e, // i64
'f': 0x7d, // f32
'd': 0x7c, // f64
};
// Parameters, length + signatures
typeSection.push(sigParam.length);
for (var i = 0; i < sigParam.length; ++i) {
typeSection.push(typeCodes[sigParam[i]]);
}
// Return values, length + signatures
// With no multi-return in MVP, either 0 (void) or 1 (anything else)
if (sigRet == 'v') {
typeSection.push(0x00);
} else {
typeSection = typeSection.concat([0x01, typeCodes[sigRet]]);
}
// Write the overall length of the type section back into the section header
// (excepting the 2 bytes for the section id and length)
typeSection[1] = typeSection.length - 2;
// Rest of the module is static
var bytes = new Uint8Array([
0x00, 0x61, 0x73, 0x6d, // magic ("\0asm")
0x01, 0x00, 0x00, 0x00, // version: 1
].concat(typeSection, [
0x02, 0x07, // import section
// (import "e" "f" (func 0 (type 0)))
0x01, 0x01, 0x65, 0x01, 0x66, 0x00, 0x00,
0x07, 0x05, // export section
// (export "f" (func 0 (type 0)))
0x01, 0x01, 0x66, 0x00, 0x00,
]));
// We can compile this wasm module synchronously because it is very small.
// This accepts an import (at "e.f"), that it reroutes to an export (at "f")
var module = new WebAssembly.Module(bytes);
var instance = new WebAssembly.Instance(module, {
e: {
f: func
}
});
var wrappedFunc = instance.exports.f;
return wrappedFunc;
}
// Add a wasm function to the table.
function addFunctionWasm(func, sig) {
var table = wasmTable;
var ret = table.length;
// Grow the table
try {
table.grow(1);
} catch (err) {
if (!err instanceof RangeError) {
throw err;
}
throw 'Unable to grow wasm table. Use a higher value for RESERVED_FUNCTION_POINTERS or set ALLOW_TABLE_GROWTH.';
}
// Insert new element
try {
// Attempting to call this with JS function will cause of table.set() to fail
table.set(ret, func);
} catch (err) {
if (!err instanceof TypeError) {
throw err;
}
assert(typeof sig !== 'undefined', 'Missing signature argument to addFunction');
var wrapped = convertJsFunctionToWasm(func, sig);
table.set(ret, wrapped);
}
return ret;
}
function removeFunctionWasm(index) {
// TODO(sbc): Look into implementing this to allow re-using of table slots
}
// 'sig' parameter is required for the llvm backend but only when func is not
// already a WebAssembly function.
function addFunction(func, sig) {
assert(typeof func !== 'undefined');
var base = 0;
for (var i = base; i < base + 64; i++) {
if (!functionPointers[i]) {
functionPointers[i] = func;
return jsCallStartIndex + i;
}
}
throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
}
function removeFunction(index) {
functionPointers[index-jsCallStartIndex] = null;
}
var funcWrappers = {};
function getFuncWrapper(func, sig) {
if (!func) return; // on null pointer, return undefined
assert(sig);
if (!funcWrappers[sig]) {
funcWrappers[sig] = {};
}
var sigCache = funcWrappers[sig];
if (!sigCache[func]) {
// optimize away arguments usage in common cases
if (sig.length === 1) {
sigCache[func] = function dynCall_wrapper() {
return dynCall(sig, func);
};
} else if (sig.length === 2) {
sigCache[func] = function dynCall_wrapper(arg) {
return dynCall(sig, func, [arg]);
};
} else {
// general case
sigCache[func] = function dynCall_wrapper() {
return dynCall(sig, func, Array.prototype.slice.call(arguments));
};
}
}
return sigCache[func];
}
function makeBigInt(low, high, unsigned) {
return unsigned ? ((+((low>>>0)))+((+((high>>>0)))*4294967296.0)) : ((+((low>>>0)))+((+((high|0)))*4294967296.0));
}
function dynCall(sig, ptr, args) {
if (args && args.length) {
assert(args.length == sig.length-1);
assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\'');
return Module['dynCall_' + sig].apply(null, [ptr].concat(args));
} else {
assert(sig.length == 1);
assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\'');
return Module['dynCall_' + sig].call(null, ptr);