sqlite: support TypedArray and DataView in `StatementSync`

Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/56385
Fixes: https://github.com/nodejs/node/issues/56384
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
pull/56479/head
Alex Yang 2025-01-05 03:18:36 -08:00 committed by GitHub
parent 383e1a281b
commit 08b7d38aa4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 83 additions and 6 deletions

View File

@ -339,11 +339,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
@ -371,11 +375,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
@ -391,11 +399,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
@ -410,11 +422,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

View File

@ -960,7 +960,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;
@ -1065,7 +1065,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);

View File

@ -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));
}
});
}
});