Skip to content

Commit

Permalink
sqlite: support ArrayBuffer and TypedArray in StatementSync
Browse files Browse the repository at this point in the history
  • Loading branch information
himself65 committed Dec 28, 2024
1 parent ca3c8f1 commit aa1218f
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 6 deletions.
8 changes: 4 additions & 4 deletions doc/api/sqlite.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ added: v22.5.0

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

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

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

* `namedParameters` {Object} An optional object used to bind named parameters.
The keys of this object are used to configure the mapping.
* `...anonymousParameters` {null|number|bigint|string|Buffer|Uint8Array} Zero or
* `...anonymousParameters` {null|number|bigint|string|Buffer|Uint8Array|TypedArray} Zero or
more values to bind to anonymous parameters.
* Returns: {Object}
* `changes`: {number|bigint} The number of rows modified, inserted, or deleted
Expand Down
6 changes: 4 additions & 2 deletions src/node_sqlite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,8 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
int anon_idx = 1;
int anon_start = 0;

if (args[0]->IsObject() && !args[0]->IsUint8Array()) {
if (args[0]->IsObject() && !args[0]->IsUint8Array() &&
!args[0]->IsTypedArray() && !args[0]->IsArrayBuffer()) {
Local<Object> obj = args[0].As<Object>();
Local<Context> context = obj->GetIsolate()->GetCurrentContext();
Local<Array> keys;
Expand Down Expand Up @@ -1035,7 +1036,8 @@ bool StatementSync::BindValue(const Local<Value>& value, const int index) {
statement_, index, *val, val.length(), SQLITE_TRANSIENT);
} else if (value->IsNull()) {
r = sqlite3_bind_null(statement_, index);
} else if (value->IsUint8Array()) {
} else if (value->IsUint8Array() || value->IsArrayBufferView() ||
value->IsArrayBuffer()) {
ArrayBufferViewContents<uint8_t> buf(value);
r = sqlite3_bind_blob(
statement_, index, buf.data(), buf.length(), SQLITE_TRANSIENT);
Expand Down
61 changes: 61 additions & 0 deletions test/parallel/test-sqlite-typed-array.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use strict';
require('../common');
const tmpdir = require('../common/tmpdir');
const { join } = require('node:path');
const { DatabaseSync } = require('node:sqlite');
const { suite, test } = require('node:test');
let cnt = 0;

tmpdir.refresh();

function nextDb() {
return join(tmpdir.path, `database-${cnt++}.db`);
}

const arrayBuffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]).buffer;
const TypedArrays = [
['Int8Array', Int8Array],
['Uint8Array', Uint8Array],
['Uint8ClampedArray', Uint8ClampedArray],
['Int16Array', Int16Array],
['Uint16Array', Uint16Array],
['Int32Array', Int32Array],
['Uint32Array', Uint32Array],
['Float32Array', Float32Array],
['Float64Array', Float64Array],
['BigInt64Array', BigInt64Array],
['BigUint64Array', BigUint64Array],
['DataView', DataView],
];

suite('StatementSync with TypedArray', () => {
for (const [displayName, TypedArray] of TypedArrays) {
test(displayName, (t) => {
const db = new DatabaseSync(nextDb());
t.after(() => { db.close(); });
db.exec('CREATE TABLE test (data BLOB)');
// insert
{
const stmt = db.prepare('INSERT INTO test VALUES (?)');
stmt.run(new TypedArray(arrayBuffer));
}
// select all
{
const stmt = db.prepare('SELECT * FROM test');
const row = stmt.get();
t.assert.ok(row.data instanceof Uint8Array);

Check failure on line 46 in test/parallel/test-sqlite-typed-array.js

View workflow job for this annotation

GitHub Actions / test-linux

--- stderr --- (node:175278) ExperimentalWarning: SQLite is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) --- stdout --- β–Ά StatementSync with TypedArray βœ” Int8Array (7.461747ms) βœ” Uint8Array (10.175331ms) βœ” Uint8ClampedArray (8.376427ms) βœ” Int16Array (7.689852ms) ::debug::starting to run StatementSync with TypedArray ::debug::starting to run Int8Array ::debug::completed running Int8Array ::debug::starting to run Uint8Array ::debug::completed running Uint8Array ::debug::starting to run Uint8ClampedArray ::debug::completed running Uint8ClampedArray ::debug::starting to run Int16Array ::debug::completed running Int16Array βœ” Uint16Array (8.124498ms) βœ” Int32Array (7.65758ms) βœ” Uint32Array (5.533873ms) βœ” Float32Array (4.72418ms) ::debug::starting to run Uint16Array ::debug::completed running Uint16Array ::debug::starting to run Int32Array ::debug::completed running Int32Array ::debug::starting to run Uint32Array ::debug::completed running Uint32Array ::debug::starting to run Float32Array ::debug::completed running Float32Array βœ” Float64Array (3.937391ms) βœ” BigInt64Array (4.012465ms) βœ” BigUint64Array (3.991448ms) βœ– DataView (10.659931ms) AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value: t.assert.ok(row.data instanceof Uint8Array) at TestContext.<anonymous> (/home/runner/work/node/node/test/parallel/test-sqlite-typed-array.js:46:18) at Test.runInAsyncScope (node:async_hooks:211:14) at Test.run (node:internal/test_runner/test:931:25) at Suite.processPendingSubtests (node:internal/test_runner/test:629:18) at Test.postRun (node:internal/test_runner/test:1042:19) at Test.run (node:internal/test_runner/test:970:12) at process.processTicksAndRejections (node:internal/process/task_queues:105:5) at async Suite.processPendingSubtests (node:internal/test_runner/test:629:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: false, expected: true, operator: '==' } ::debug::starting to run Float64Array ::debug::completed running Float64Array ::debug::starting to run BigInt64Array ::debug::completed running BigInt64Array ::debug::starting to run BigUint64Array ::debug::completed running BigUint64Array ::debug::starting to run DataView ::error title=DataView,file=test/parallel/test-sqlite-typed-array.js,line=46,col=18::[Error [ERR_TEST_FAILURE]: The expression evaluated to a falsy value: t.assert.ok(row.data instanceof Uint8Array) ] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value: t.assert.ok(row.data instanceof Uint8Array) at TestContext.<anonymous> (/home/runner/work/node/node/test/parallel/test-sqlite-typed-array.js:46:18) at Test.runInAsyncScope (node:async_hooks:211:14) at Test.run (node:internal/test_runner/test:931:25) at Suite.processPendingSubtests (node:internal/test_runner/test:629:18) at Test.postRun (node:internal/test_runner/test:1042:19) at Test.run (node:internal/test_runner/test:970:12) at process.processTicksAndRejections (node:internal/process/task_queues:105:5) at async Suite.processPendingSubtests (node:internal/test_runner/test:629:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: false, expected: true, operator: '==' } } βœ– StatementSync with TypedArray (84.243147ms) β„Ή tests 12 β„Ή suites 1 β„Ή pass 11 β„Ή fail 1 β„Ή cancelled 0 β„Ή skipped 0 β„Ή todo 0 β„Ή duration_ms 191.091147 βœ– failing tests: test at test/parallel/test-sqlite-typed-array.js:33:5 βœ– DataView (10.659931ms) AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value: t.assert.ok(row.data instanceof Uint8Array) at TestContext.<anonymous> (/home/runner/work/node/node/test/parallel/test-sqlite-typed-array.js:46:18) at Test.runInAsyncScope (node:async_hooks:211:14) at Test.run (node:internal

Check failure on line 46 in test/parallel/test-sqlite-typed-array.js

View workflow job for this annotation

GitHub Actions / test-macOS (macos-13)

--- stderr --- (node:64422) ExperimentalWarning: SQLite is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) --- stdout --- β–Ά StatementSync with TypedArray βœ” Int8Array (7.837676ms) βœ” Uint8Array (4.336773ms) βœ” Uint8ClampedArray (4.059945ms) βœ” Int16Array (3.972863ms) ::debug::starting to run StatementSync with TypedArray ::debug::starting to run Int8Array ::debug::completed running Int8Array ::debug::starting to run Uint8Array ::debug::completed running Uint8Array ::debug::starting to run Uint8ClampedArray ::debug::completed running Uint8ClampedArray ::debug::starting to run Int16Array ::debug::completed running Int16Array βœ” Uint16Array (5.660974ms) βœ” Int32Array (4.283519ms) βœ” Uint32Array (4.804127ms) βœ” Float32Array (3.803875ms) ::debug::starting to run Uint16Array ::debug::completed running Uint16Array ::debug::starting to run Int32Array ::debug::completed running Int32Array ::debug::starting to run Uint32Array ::debug::completed running Uint32Array ::debug::starting to run Float32Array ::debug::completed running Float32Array βœ” Float64Array (4.43202ms) βœ” BigInt64Array (4.703208ms) βœ” BigUint64Array (3.591104ms) βœ– DataView (13.650415ms) AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value: t.assert.ok(row.data instanceof Uint8Array) at TestContext.<anonymous> (/Users/runner/work/node/node/test/parallel/test-sqlite-typed-array.js:46:18) at Test.runInAsyncScope (node:async_hooks:211:14) at Test.run (node:internal/test_runner/test:931:25) at Suite.processPendingSubtests (node:internal/test_runner/test:629:18) at Test.postRun (node:internal/test_runner/test:1042:19) at Test.run (node:internal/test_runner/test:970:12) at process.processTicksAndRejections (node:internal/process/task_queues:105:5) at async Suite.processPendingSubtests (node:internal/test_runner/test:629:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: false, expected: true, operator: '==' } ::debug::starting to run Float64Array ::debug::completed running Float64Array ::debug::starting to run BigInt64Array ::debug::completed running BigInt64Array ::debug::starting to run BigUint64Array ::debug::completed running BigUint64Array ::debug::starting to run DataView ::error title=DataView,file=test/parallel/test-sqlite-typed-array.js,line=46,col=18::[Error [ERR_TEST_FAILURE]: The expression evaluated to a falsy value: t.assert.ok(row.data instanceof Uint8Array) ] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value: t.assert.ok(row.data instanceof Uint8Array) at TestContext.<anonymous> (/Users/runner/work/node/node/test/parallel/test-sqlite-typed-array.js:46:18) at Test.runInAsyncScope (node:async_hooks:211:14) at Test.run (node:internal/test_runner/test:931:25) at Suite.processPendingSubtests (node:internal/test_runner/test:629:18) at Test.postRun (node:internal/test_runner/test:1042:19) at Test.run (node:internal/test_runner/test:970:12) at process.processTicksAndRejections (node:internal/process/task_queues:105:5) at async Suite.processPendingSubtests (node:internal/test_runner/test:629:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: false, expected: true, operator: '==' } } βœ– StatementSync with TypedArray (67.484656ms) β„Ή tests 12 β„Ή suites 1 β„Ή pass 11 β„Ή fail 1 β„Ή cancelled 0 β„Ή skipped 0 β„Ή todo 0 β„Ή duration_ms 207.074428 βœ– failing tests: test at test/parallel/test-sqlite-typed-array.js:33:5 βœ– DataView (13.650415ms) AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value: t.assert.ok(row.data instanceof Uint8Array) at TestContext.<anonymous> (/Users/runner/work/node/node/test/parallel/test-sqlite-typed-array.js:46:18) at Test.runInAsyncScope (node:async_hooks:211:14) at Test.run (node:intern

Check failure on line 46 in test/parallel/test-sqlite-typed-array.js

View workflow job for this annotation

GitHub Actions / test-macOS (macos-14)

--- stderr --- (node:85756) ExperimentalWarning: SQLite is an experimental feature and might change at any time (Use `node --trace-warnings ...` to show where the warning was created) --- stdout --- β–Ά StatementSync with TypedArray βœ” Int8Array (2.784125ms) βœ” Uint8Array (0.981125ms) βœ” Uint8ClampedArray (1.0965ms) βœ” Int16Array (0.946917ms) ::debug::starting to run StatementSync with TypedArray ::debug::starting to run Int8Array ::debug::completed running Int8Array ::debug::starting to run Uint8Array ::debug::completed running Uint8Array ::debug::starting to run Uint8ClampedArray ::debug::completed running Uint8ClampedArray ::debug::starting to run Int16Array ::debug::completed running Int16Array βœ” Uint16Array (1.183958ms) βœ” Int32Array (0.93425ms) βœ” Uint32Array (1.031125ms) βœ” Float32Array (0.887917ms) ::debug::starting to run Uint16Array ::debug::completed running Uint16Array ::debug::starting to run Int32Array ::debug::completed running Int32Array ::debug::starting to run Uint32Array ::debug::completed running Uint32Array ::debug::starting to run Float32Array ::debug::completed running Float32Array βœ” Float64Array (0.976375ms) βœ” BigInt64Array (0.914708ms) βœ” BigUint64Array (2.21525ms) βœ– DataView (4.927833ms) AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value: t.assert.ok(row.data instanceof Uint8Array) at TestContext.<anonymous> (/Users/runner/work/node/node/test/parallel/test-sqlite-typed-array.js:46:18) at Test.runInAsyncScope (node:async_hooks:211:14) at Test.run (node:internal/test_runner/test:931:25) at Suite.processPendingSubtests (node:internal/test_runner/test:629:18) at Test.postRun (node:internal/test_runner/test:1042:19) at Test.run (node:internal/test_runner/test:970:12) at process.processTicksAndRejections (node:internal/process/task_queues:105:5) at async Suite.processPendingSubtests (node:internal/test_runner/test:629:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: false, expected: true, operator: '==' } ::debug::starting to run Float64Array ::debug::completed running Float64Array ::debug::starting to run BigInt64Array ::debug::completed running BigInt64Array ::debug::starting to run BigUint64Array ::debug::completed running BigUint64Array ::debug::starting to run DataView ::error title=DataView,file=test/parallel/test-sqlite-typed-array.js,line=46,col=18::[Error [ERR_TEST_FAILURE]: The expression evaluated to a falsy value: t.assert.ok(row.data instanceof Uint8Array) ] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value: t.assert.ok(row.data instanceof Uint8Array) at TestContext.<anonymous> (/Users/runner/work/node/node/test/parallel/test-sqlite-typed-array.js:46:18) at Test.runInAsyncScope (node:async_hooks:211:14) at Test.run (node:internal/test_runner/test:931:25) at Suite.processPendingSubtests (node:internal/test_runner/test:629:18) at Test.postRun (node:internal/test_runner/test:1042:19) at Test.run (node:internal/test_runner/test:970:12) at process.processTicksAndRejections (node:internal/process/task_queues:105:5) at async Suite.processPendingSubtests (node:internal/test_runner/test:629:7) { generatedMessage: true, code: 'ERR_ASSERTION', actual: false, expected: true, operator: '==' } } βœ– StatementSync with TypedArray (19.702083ms) β„Ή tests 12 β„Ή suites 1 β„Ή pass 11 β„Ή fail 1 β„Ή cancelled 0 β„Ή skipped 0 β„Ή todo 0 β„Ή duration_ms 77.778542 βœ– failing tests: test at test/parallel/test-sqlite-typed-array.js:33:5 βœ– DataView (4.927833ms) AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value: t.assert.ok(row.data instanceof Uint8Array) at TestContext.<anonymous> (/Users/runner/work/node/node/test/parallel/test-sqlite-typed-array.js:46:18) at Test.runInAsyncScope (node:async_hooks:211:14) at Test.run (node:internal/tes
t.assert.strictEqual(row.data.length, 8);
t.assert.deepStrictEqual(row.data, new Uint8Array(arrayBuffer));
}
// query
{
const stmt = db.prepare('SELECT * FROM test WHERE data = ?');
const rows = stmt.all(new TypedArray(arrayBuffer));
t.assert.strictEqual(rows.length, 1);
t.assert.ok(rows[0].data instanceof Uint8Array);
t.assert.strictEqual(rows[0].data.length, 8);
t.assert.deepStrictEqual(rows[0].data, new Uint8Array(arrayBuffer));
}
});
}
});

0 comments on commit aa1218f

Please sign in to comment.