mirror of
https://github.com/nodejs/node.git
synced 2026-10-14 10:26:26 -04:00
sqlite: add support for unknown named parameters
This commit adds a method for toggling support for unknown named parameters in prepared statements. Fixes: https://github.com/nodejs/node/issues/55533 PR-URL: https://github.com/nodejs/node/pull/57552 Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
1 parent
ace5548ff0
commit
ffc1cf6205
4 files changed
+84
-3
No files matched your search
@@ -542,6 +542,17 @@ are several caveats to be aware of when enabling bare named parameters:
|
||||
statement will result in an exception as it cannot be determined how to bind
|
||||
a bare name.
|
||||
|
||||
### `statement.setAllowUnknownNamedParameters(enabled)`
|
||||
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
* `enabled` {boolean} Enables or disables support for unknown named parameters.
|
||||
|
||||
By default, if an unknown name is encountered while binding parameters, an
|
||||
exception is thrown. This method allows unknown named parameters to be ignored.
|
||||
|
||||
### `statement.setReadBigInts(enabled)`
|
||||
|
||||
<!-- YAML
|
||||
|
||||
+29
-3
@@ -1361,6 +1361,7 @@ StatementSync::StatementSync(Environment* env,
|
||||
// connection level and inherited by statements to reduce boilerplate.
|
||||
use_big_ints_ = false;
|
||||
allow_bare_named_params_ = true;
|
||||
allow_unknown_named_params_ = false;
|
||||
bare_named_params_ = std::nullopt;
|
||||
}
|
||||
|
||||
@@ -1443,9 +1444,13 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
THROW_ERR_INVALID_STATE(
|
||||
env(), "Unknown named parameter '%s'", *utf8_key);
|
||||
return false;
|
||||
if (allow_unknown_named_params_) {
|
||||
continue;
|
||||
} else {
|
||||
THROW_ERR_INVALID_STATE(
|
||||
env(), "Unknown named parameter '%s'", *utf8_key);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2033,6 +2038,23 @@ void StatementSync::SetAllowBareNamedParameters(
|
||||
stmt->allow_bare_named_params_ = args[0]->IsTrue();
|
||||
}
|
||||
|
||||
void StatementSync::SetAllowUnknownNamedParameters(
|
||||
const FunctionCallbackInfo<Value>& args) {
|
||||
StatementSync* stmt;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
THROW_AND_RETURN_ON_BAD_STATE(
|
||||
env, stmt->IsFinalized(), "statement has been finalized");
|
||||
|
||||
if (!args[0]->IsBoolean()) {
|
||||
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
|
||||
"The \"enabled\" argument must be a boolean.");
|
||||
return;
|
||||
}
|
||||
|
||||
stmt->allow_unknown_named_params_ = args[0]->IsTrue();
|
||||
}
|
||||
|
||||
void StatementSync::SetReadBigInts(const FunctionCallbackInfo<Value>& args) {
|
||||
StatementSync* stmt;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
|
||||
@@ -2098,6 +2120,10 @@ Local<FunctionTemplate> StatementSync::GetConstructorTemplate(
|
||||
tmpl,
|
||||
"setAllowBareNamedParameters",
|
||||
StatementSync::SetAllowBareNamedParameters);
|
||||
SetProtoMethod(isolate,
|
||||
tmpl,
|
||||
"setAllowUnknownNamedParameters",
|
||||
StatementSync::SetAllowUnknownNamedParameters);
|
||||
SetProtoMethod(
|
||||
isolate, tmpl, "setReadBigInts", StatementSync::SetReadBigInts);
|
||||
env->set_sqlite_statement_sync_constructor_template(tmpl);
|
||||
|
||||
@@ -123,6 +123,8 @@ class StatementSync : public BaseObject {
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void SetAllowBareNamedParameters(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void SetAllowUnknownNamedParameters(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void SetReadBigInts(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
void Finalize();
|
||||
bool IsFinalized();
|
||||
@@ -136,6 +138,7 @@ class StatementSync : public BaseObject {
|
||||
sqlite3_stmt* statement_;
|
||||
bool use_big_ints_;
|
||||
bool allow_bare_named_params_;
|
||||
bool allow_unknown_named_params_;
|
||||
std::optional<std::map<std::string, std::string>> bare_named_params_;
|
||||
bool BindParams(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
bool BindValue(const v8::Local<v8::Value>& value, const int index);
|
||||
|
||||
@@ -77,3 +77,44 @@ suite('named parameters', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('StatementSync.prototype.setAllowUnknownNamedParameters()', () => {
|
||||
test('unknown named parameter support can be toggled', (t) => {
|
||||
const db = new DatabaseSync(':memory:');
|
||||
t.after(() => { db.close(); });
|
||||
const setup = db.exec(
|
||||
'CREATE TABLE data(key INTEGER, val INTEGER) STRICT;'
|
||||
);
|
||||
t.assert.strictEqual(setup, undefined);
|
||||
const stmt = db.prepare('INSERT INTO data (key, val) VALUES ($k, $v)');
|
||||
t.assert.strictEqual(stmt.setAllowUnknownNamedParameters(true), undefined);
|
||||
const params = { $a: 1, $b: 2, $k: 42, $y: 25, $v: 84, $z: 99 };
|
||||
t.assert.deepStrictEqual(
|
||||
stmt.run(params),
|
||||
{ changes: 1, lastInsertRowid: 1 },
|
||||
);
|
||||
t.assert.strictEqual(stmt.setAllowUnknownNamedParameters(false), undefined);
|
||||
t.assert.throws(() => {
|
||||
stmt.run(params);
|
||||
}, {
|
||||
code: 'ERR_INVALID_STATE',
|
||||
message: /Unknown named parameter '\$a'/,
|
||||
});
|
||||
});
|
||||
|
||||
test('throws when input is not a boolean', (t) => {
|
||||
const db = new DatabaseSync(':memory:');
|
||||
t.after(() => { db.close(); });
|
||||
const setup = db.exec(
|
||||
'CREATE TABLE data(key INTEGER PRIMARY KEY, val INTEGER) STRICT;'
|
||||
);
|
||||
t.assert.strictEqual(setup, undefined);
|
||||
const stmt = db.prepare('INSERT INTO data (key, val) VALUES ($k, $v)');
|
||||
t.assert.throws(() => {
|
||||
stmt.setAllowUnknownNamedParameters();
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
message: /The "enabled" argument must be a boolean/,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user