Skip to content

Commit baad65c

Browse files
authored
Added partial BigInt support (sql-js#471)
* Added partial BigInt support Moved from es6 to support bigint Changed from getNumber to getBigInt Avoided blobal redeclaration of function/variables Improved BigInt support, handled bind params for bigInt Logical change on how big int is supported BigInt is not fully supported at WASM level Added config to enable and disable bigInt support Added documentation Changed var to const as per readme standard * Changes as per PR comments * Changes as per PR comments - future extension support
1 parent 33b6674 commit baad65c

File tree

4 files changed

+103
-9
lines changed

4 files changed

+103
-9
lines changed

README.md

+27
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,33 @@ Example:
231231
});
232232
</script>
233233
```
234+
### Enabling BigInt support
235+
If you need ```BigInt``` support, it is partially supported since most browsers now supports it including Safari.Binding ```BigInt``` is still not supported, only getting ```BigInt``` from the database is supported for now.
236+
237+
```html
238+
<script>
239+
const stmt = db.prepare("SELECT * FROM test");
240+
const config = {useBigInt: true};
241+
/*Pass optional config param to the get function*/
242+
while (stmt.step()) console.log(stmt.get(null, config));
243+
244+
/*OR*/
245+
const result = db.exec("SELECT * FROM test", config);
246+
console.log(results[0].values)
247+
</script>
248+
```
249+
On WebWorker, you can just add ```config``` param before posting a message. With this, you wont have to pass config param on ```get``` function.
250+
251+
```html
252+
<script>
253+
worker.postMessage({
254+
id:1,
255+
action:"exec",
256+
sql: "SELECT * FROM test",
257+
config: {useBigInt: true}, /*Optional param*/
258+
});
259+
</script>
260+
```
234261

235262
See [examples/GUI/gui.js](examples/GUI/gui.js) for a full working example.
236263

src/api.js

+38-7
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
116116
"number",
117117
["number", "number", "number"]
118118
);
119+
119120
var sqlite3_bind_parameter_index = cwrap(
120121
"sqlite3_bind_parameter_index",
121122
"number",
@@ -358,6 +359,19 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
358359
return sqlite3_column_double(this.stmt, pos);
359360
};
360361

362+
Statement.prototype.getBigInt = function getBigInt(pos) {
363+
if (pos == null) {
364+
pos = this.pos;
365+
this.pos += 1;
366+
}
367+
var text = sqlite3_column_text(this.stmt, pos);
368+
if (typeof BigInt !== "function") {
369+
throw new Error("BigInt is not supported");
370+
}
371+
/* global BigInt */
372+
return BigInt(text);
373+
};
374+
361375
Statement.prototype.getString = function getString(pos) {
362376
if (pos == null) {
363377
pos = this.pos;
@@ -390,8 +404,13 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
390404
<caption>Print all the rows of the table test to the console</caption>
391405
var stmt = db.prepare("SELECT * FROM test");
392406
while (stmt.step()) console.log(stmt.get());
407+
408+
<caption>Enable BigInt support</caption>
409+
var stmt = db.prepare("SELECT * FROM test");
410+
while (stmt.step()) console.log(stmt.get(null, {useBigInt: true}));
393411
*/
394-
Statement.prototype["get"] = function get(params) {
412+
Statement.prototype["get"] = function get(params, config) {
413+
config = config || {};
395414
if (params != null && this["bind"](params)) {
396415
this["step"]();
397416
}
@@ -400,6 +419,11 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
400419
for (var field = 0; field < ref; field += 1) {
401420
switch (sqlite3_column_type(this.stmt, field)) {
402421
case SQLITE_INTEGER:
422+
var getfunc = config["useBigInt"]
423+
? this.getBigInt(field)
424+
: this.getNumber(field);
425+
results1.push(getfunc);
426+
break;
403427
case SQLITE_FLOAT:
404428
results1.push(this.getNumber(field));
405429
break;
@@ -451,8 +475,8 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
451475
console.log(stmt.getAsObject());
452476
// Will print {nbr:5, data: Uint8Array([1,2,3]), null_value:null}
453477
*/
454-
Statement.prototype["getAsObject"] = function getAsObject(params) {
455-
var values = this["get"](params);
478+
Statement.prototype["getAsObject"] = function getAsObject(params, config) {
479+
var values = this["get"](params, config);
456480
var names = this["getColumnNames"]();
457481
var rowObject = {};
458482
for (var i = 0; i < names.length; i += 1) {
@@ -560,10 +584,15 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
560584
pos = this.pos;
561585
this.pos += 1;
562586
}
587+
563588
switch (typeof val) {
564589
case "string":
565590
return this.bindString(val, pos);
566591
case "number":
592+
return this.bindNumber(val + 0, pos);
593+
case "bigint":
594+
// BigInt is not fully supported yet at WASM level.
595+
return this.bindString(val.toString(), pos);
567596
case "boolean":
568597
return this.bindNumber(val + 0, pos);
569598
case "object":
@@ -899,7 +928,7 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
899928
(separated by `;`). This limitation does not apply to params as an object.
900929
* @return {Database.QueryExecResult[]} The results of each statement
901930
*/
902-
Database.prototype["exec"] = function exec(sql, params) {
931+
Database.prototype["exec"] = function exec(sql, params, config) {
903932
if (!this.db) {
904933
throw "Database closed";
905934
}
@@ -937,7 +966,7 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
937966
};
938967
results.push(curresult);
939968
}
940-
curresult["values"].push(stmt["get"]());
969+
curresult["values"].push(stmt["get"](null, config));
941970
}
942971
stmt["free"]();
943972
}
@@ -971,7 +1000,9 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
9711000
function (row){console.log(row.name + " is a grown-up.")}
9721001
);
9731002
*/
974-
Database.prototype["each"] = function each(sql, params, callback, done) {
1003+
Database.prototype["each"] = function each(
1004+
sql, params, callback, done, config
1005+
) {
9751006
var stmt;
9761007
if (typeof params === "function") {
9771008
done = callback;
@@ -981,7 +1012,7 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
9811012
stmt = this["prepare"](sql, params);
9821013
try {
9831014
while (stmt["step"]()) {
984-
callback(stmt["getAsObject"]());
1015+
callback(stmt["getAsObject"](null, config));
9851016
}
9861017
} finally {
9871018
stmt["free"]();

src/worker.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ function onModuleReady(SQL) {
1515

1616
var buff; var data; var result;
1717
data = this["data"];
18+
var config = data["config"] ? data["config"] : {};
1819
switch (data && data["action"]) {
1920
case "open":
2021
buff = data["buffer"];
@@ -32,7 +33,7 @@ function onModuleReady(SQL) {
3233
}
3334
return postMessage({
3435
id: data["id"],
35-
results: db.exec(data["sql"], data["params"])
36+
results: db.exec(data["sql"], data["params"], config)
3637
});
3738
case "each":
3839
if (db === null) {
@@ -51,7 +52,7 @@ function onModuleReady(SQL) {
5152
finished: true
5253
});
5354
};
54-
return db.each(data["sql"], data["params"], callback, done);
55+
return db.each(data["sql"], data["params"], callback, done, config);
5556
case "export":
5657
buff = db["export"]();
5758
result = {

test/test_big_int.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
exports.test = function(sql, assert){
2+
// Create a database
3+
var db = new sql.Database();
4+
5+
// Create table, insert data
6+
sqlstr = "CREATE TABLE IF NOT EXISTS Test_BigInt (someNumber BIGINT NOT NULL);" +
7+
"INSERT INTO Test_BigInt (someNumber) VALUES (1628675501000);";
8+
db.exec(sqlstr);
9+
10+
var config = {useBigInt: true};
11+
12+
var stmt = db.prepare("SELECT * FROM Test_BigInt;");
13+
stmt.step();
14+
15+
assert.strictEqual(typeof stmt.get()[0], 'number', "Reading number value");
16+
assert.strictEqual(typeof stmt.get(null, config)[0], 'bigint', "Reading bigint value");
17+
18+
db.close();
19+
};
20+
21+
if (module == require.main) {
22+
const target_file = process.argv[2];
23+
const sql_loader = require('./load_sql_lib');
24+
sql_loader(target_file).then((sql)=>{
25+
require('test').run({
26+
'test big int': function(assert){
27+
exports.test(sql, assert);
28+
}
29+
});
30+
})
31+
.catch((e)=>{
32+
console.error(e);
33+
assert.fail(e);
34+
});
35+
}

0 commit comments

Comments
 (0)