Skip to content

Commit a89ce39

Browse files
committed
sqlite: support TypedArray and DataView in StatementSync
1 parent ca3c8f1 commit a89ce39

File tree

3 files changed

+70
-6
lines changed

3 files changed

+70
-6
lines changed

doc/api/sqlite.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ added: v22.5.0
326326

327327
* `namedParameters` {Object} An optional object used to bind named parameters.
328328
The keys of this object are used to configure the mapping.
329-
* `...anonymousParameters` {null|number|bigint|string|Buffer|Uint8Array} Zero or
329+
* `...anonymousParameters` {null|number|bigint|string|Buffer|Uint8Array|TypedArray} Zero or
330330
more values to bind to anonymous parameters.
331331
* Returns: {Array} An array of objects. Each object corresponds to a row
332332
returned by executing the prepared statement. The keys and values of each
@@ -358,7 +358,7 @@ added: v22.5.0
358358

359359
* `namedParameters` {Object} An optional object used to bind named parameters.
360360
The keys of this object are used to configure the mapping.
361-
* `...anonymousParameters` {null|number|bigint|string|Buffer|Uint8Array} Zero or
361+
* `...anonymousParameters` {null|number|bigint|string|Buffer|Uint8Array|TypedArray} Zero or
362362
more values to bind to anonymous parameters.
363363
* Returns: {Object|undefined} An object corresponding to the first row returned
364364
by executing the prepared statement. The keys and values of the object
@@ -378,7 +378,7 @@ added: v23.4.0
378378

379379
* `namedParameters` {Object} An optional object used to bind named parameters.
380380
The keys of this object are used to configure the mapping.
381-
* `...anonymousParameters` {null|number|bigint|string|Buffer|Uint8Array} Zero or
381+
* `...anonymousParameters` {null|number|bigint|string|Buffer|Uint8Array|TypedArray} Zero or
382382
more values to bind to anonymous parameters.
383383
* Returns: {Iterator} An iterable iterator of objects. Each object corresponds to a row
384384
returned by executing the prepared statement. The keys and values of each
@@ -397,7 +397,7 @@ added: v22.5.0
397397

398398
* `namedParameters` {Object} An optional object used to bind named parameters.
399399
The keys of this object are used to configure the mapping.
400-
* `...anonymousParameters` {null|number|bigint|string|Buffer|Uint8Array} Zero or
400+
* `...anonymousParameters` {null|number|bigint|string|Buffer|Uint8Array|TypedArray} Zero or
401401
more values to bind to anonymous parameters.
402402
* Returns: {Object}
403403
* `changes`: {number|bigint} The number of rows modified, inserted, or deleted

src/node_sqlite.cc

+5-2
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,9 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
930930
int anon_idx = 1;
931931
int anon_start = 0;
932932

933-
if (args[0]->IsObject() && !args[0]->IsUint8Array()) {
933+
if (args[0]->IsObject() && !args[0]->IsUint8Array() &&
934+
!args[0]->IsTypedArray() && !args[0]->IsArrayBuffer() &&
935+
!args[0]->IsDataView()) {
934936
Local<Object> obj = args[0].As<Object>();
935937
Local<Context> context = obj->GetIsolate()->GetCurrentContext();
936938
Local<Array> keys;
@@ -1035,7 +1037,8 @@ bool StatementSync::BindValue(const Local<Value>& value, const int index) {
10351037
statement_, index, *val, val.length(), SQLITE_TRANSIENT);
10361038
} else if (value->IsNull()) {
10371039
r = sqlite3_bind_null(statement_, index);
1038-
} else if (value->IsUint8Array()) {
1040+
} else if (value->IsArrayBufferView() || value->IsArrayBuffer() ||
1041+
value->IsDataView()) {
10391042
ArrayBufferViewContents<uint8_t> buf(value);
10401043
r = sqlite3_bind_blob(
10411044
statement_, index, buf.data(), buf.length(), SQLITE_TRANSIENT);
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
'use strict';
2+
require('../common');
3+
const tmpdir = require('../common/tmpdir');
4+
const { join } = require('node:path');
5+
const { DatabaseSync } = require('node:sqlite');
6+
const { suite, test } = require('node:test');
7+
let cnt = 0;
8+
9+
tmpdir.refresh();
10+
11+
function nextDb() {
12+
return join(tmpdir.path, `database-${cnt++}.db`);
13+
}
14+
15+
const arrayBuffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]).buffer;
16+
const TypedArrays = [
17+
['Int8Array', Int8Array],
18+
['Uint8Array', Uint8Array],
19+
['Uint8ClampedArray', Uint8ClampedArray],
20+
['Int16Array', Int16Array],
21+
['Uint16Array', Uint16Array],
22+
['Int32Array', Int32Array],
23+
['Uint32Array', Uint32Array],
24+
['Float32Array', Float32Array],
25+
['Float64Array', Float64Array],
26+
['BigInt64Array', BigInt64Array],
27+
['BigUint64Array', BigUint64Array],
28+
['DataView', DataView],
29+
];
30+
31+
suite('StatementSync with TypedArray', () => {
32+
for (const [displayName, TypedArray] of TypedArrays) {
33+
test(displayName, (t) => {
34+
const db = new DatabaseSync(nextDb());
35+
t.after(() => { db.close(); });
36+
db.exec('CREATE TABLE test (data BLOB)');
37+
// insert
38+
{
39+
const stmt = db.prepare('INSERT INTO test VALUES (?)');
40+
stmt.run(new TypedArray(arrayBuffer));
41+
}
42+
// select all
43+
{
44+
const stmt = db.prepare('SELECT * FROM test');
45+
const row = stmt.get();
46+
t.assert.ok(row.data instanceof Uint8Array);
47+
t.assert.strictEqual(row.data.length, 8);
48+
t.assert.deepStrictEqual(row.data, new Uint8Array(arrayBuffer));
49+
}
50+
// query
51+
{
52+
const stmt = db.prepare('SELECT * FROM test WHERE data = ?');
53+
const rows = stmt.all(new TypedArray(arrayBuffer));
54+
t.assert.strictEqual(rows.length, 1);
55+
t.assert.ok(rows[0].data instanceof Uint8Array);
56+
t.assert.strictEqual(rows[0].data.length, 8);
57+
t.assert.deepStrictEqual(rows[0].data, new Uint8Array(arrayBuffer));
58+
}
59+
});
60+
}
61+
});

0 commit comments

Comments
 (0)