Skip to content

sqlite: support TypedArray and DataView in StatementSync #56385

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

Merged
merged 1 commit into from
Jan 5, 2025
Merged
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
24 changes: 20 additions & 4 deletions doc/api/sqlite.md
Original file line number Diff line number Diff line change
@@ -322,11 +322,15 @@ over hand-crafted SQL strings when handling user input.

<!-- YAML
added: v22.5.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/56385
description: Add support for `DataView` and typed array objects for `anonymousParameters`.
-->

* `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|TypedArray|DataView} 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
@@ -354,11 +358,15 @@ execution of this prepared statement. This property is a wrapper around

<!-- YAML
added: v22.5.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/56385
description: Add support for `DataView` and typed array objects for `anonymousParameters`.
-->

* `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|TypedArray|DataView} 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
@@ -374,11 +382,15 @@ values in `namedParameters` and `anonymousParameters`.

<!-- YAML
added: v23.4.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/56385
description: Add support for `DataView` and typed array objects for `anonymousParameters`.
-->

* `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|TypedArray|DataView} 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
@@ -393,11 +405,15 @@ the values in `namedParameters` and `anonymousParameters`.

<!-- YAML
added: v22.5.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/56385
description: Add support for `DataView` and typed array objects for `anonymousParameters`.
-->

* `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|TypedArray|DataView} Zero or
more values to bind to anonymous parameters.
* Returns: {Object}
* `changes`: {number|bigint} The number of rows modified, inserted, or deleted
4 changes: 2 additions & 2 deletions src/node_sqlite.cc
Original file line number Diff line number Diff line change
@@ -930,7 +930,7 @@ 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]->IsArrayBufferView()) {
Local<Object> obj = args[0].As<Object>();
Local<Context> context = obj->GetIsolate()->GetCurrentContext();
Local<Array> keys;
@@ -1035,7 +1035,7 @@ 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->IsArrayBufferView()) {
ArrayBufferViewContents<uint8_t> buf(value);
r = sqlite3_bind_blob(
statement_, index, buf.data(), buf.length(), SQLITE_TRANSIENT);
61 changes: 61 additions & 0 deletions test/parallel/test-sqlite-typed-array-and-data-view.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/DataView', () => {
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);
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));
}
});
}
});