Skip to content

Commit e8d4a31

Browse files
cjihrigaduh95
authored andcommitted
sqlite: add support for unknown named parameters
This commit adds a method for toggling support for unknown named parameters in prepared statements. Fixes: #55533 PR-URL: #57552 Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent f8aff90 commit e8d4a31

File tree

4 files changed

+84
-3
lines changed

4 files changed

+84
-3
lines changed

doc/api/sqlite.md

+11
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,17 @@ are several caveats to be aware of when enabling bare named parameters:
516516
statement will result in an exception as it cannot be determined how to bind
517517
a bare name.
518518

519+
### `statement.setAllowUnknownNamedParameters(enabled)`
520+
521+
<!-- YAML
522+
added: REPLACEME
523+
-->
524+
525+
* `enabled` {boolean} Enables or disables support for unknown named parameters.
526+
527+
By default, if an unknown name is encountered while binding parameters, an
528+
exception is thrown. This method allows unknown named parameters to be ignored.
529+
519530
### `statement.setReadBigInts(enabled)`
520531

521532
<!-- YAML

src/node_sqlite.cc

+29-3
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,7 @@ StatementSync::StatementSync(Environment* env,
13611361
// connection level and inherited by statements to reduce boilerplate.
13621362
use_big_ints_ = false;
13631363
allow_bare_named_params_ = true;
1364+
allow_unknown_named_params_ = false;
13641365
bare_named_params_ = std::nullopt;
13651366
}
13661367

@@ -1443,9 +1444,13 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
14431444
}
14441445

14451446
if (r == 0) {
1446-
THROW_ERR_INVALID_STATE(
1447-
env(), "Unknown named parameter '%s'", *utf8_key);
1448-
return false;
1447+
if (allow_unknown_named_params_) {
1448+
continue;
1449+
} else {
1450+
THROW_ERR_INVALID_STATE(
1451+
env(), "Unknown named parameter '%s'", *utf8_key);
1452+
return false;
1453+
}
14491454
}
14501455
}
14511456

@@ -2033,6 +2038,23 @@ void StatementSync::SetAllowBareNamedParameters(
20332038
stmt->allow_bare_named_params_ = args[0]->IsTrue();
20342039
}
20352040

2041+
void StatementSync::SetAllowUnknownNamedParameters(
2042+
const FunctionCallbackInfo<Value>& args) {
2043+
StatementSync* stmt;
2044+
ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
2045+
Environment* env = Environment::GetCurrent(args);
2046+
THROW_AND_RETURN_ON_BAD_STATE(
2047+
env, stmt->IsFinalized(), "statement has been finalized");
2048+
2049+
if (!args[0]->IsBoolean()) {
2050+
THROW_ERR_INVALID_ARG_TYPE(env->isolate(),
2051+
"The \"enabled\" argument must be a boolean.");
2052+
return;
2053+
}
2054+
2055+
stmt->allow_unknown_named_params_ = args[0]->IsTrue();
2056+
}
2057+
20362058
void StatementSync::SetReadBigInts(const FunctionCallbackInfo<Value>& args) {
20372059
StatementSync* stmt;
20382060
ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
@@ -2098,6 +2120,10 @@ Local<FunctionTemplate> StatementSync::GetConstructorTemplate(
20982120
tmpl,
20992121
"setAllowBareNamedParameters",
21002122
StatementSync::SetAllowBareNamedParameters);
2123+
SetProtoMethod(isolate,
2124+
tmpl,
2125+
"setAllowUnknownNamedParameters",
2126+
StatementSync::SetAllowUnknownNamedParameters);
21012127
SetProtoMethod(
21022128
isolate, tmpl, "setReadBigInts", StatementSync::SetReadBigInts);
21032129
env->set_sqlite_statement_sync_constructor_template(tmpl);

src/node_sqlite.h

+3
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ class StatementSync : public BaseObject {
123123
const v8::FunctionCallbackInfo<v8::Value>& args);
124124
static void SetAllowBareNamedParameters(
125125
const v8::FunctionCallbackInfo<v8::Value>& args);
126+
static void SetAllowUnknownNamedParameters(
127+
const v8::FunctionCallbackInfo<v8::Value>& args);
126128
static void SetReadBigInts(const v8::FunctionCallbackInfo<v8::Value>& args);
127129
void Finalize();
128130
bool IsFinalized();
@@ -136,6 +138,7 @@ class StatementSync : public BaseObject {
136138
sqlite3_stmt* statement_;
137139
bool use_big_ints_;
138140
bool allow_bare_named_params_;
141+
bool allow_unknown_named_params_;
139142
std::optional<std::map<std::string, std::string>> bare_named_params_;
140143
bool BindParams(const v8::FunctionCallbackInfo<v8::Value>& args);
141144
bool BindValue(const v8::Local<v8::Value>& value, const int index);

test/parallel/test-sqlite-named-parameters.js

+41
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,44 @@ suite('named parameters', () => {
7777
});
7878
});
7979
});
80+
81+
suite('StatementSync.prototype.setAllowUnknownNamedParameters()', () => {
82+
test('unknown named parameter support can be toggled', (t) => {
83+
const db = new DatabaseSync(':memory:');
84+
t.after(() => { db.close(); });
85+
const setup = db.exec(
86+
'CREATE TABLE data(key INTEGER, val INTEGER) STRICT;'
87+
);
88+
t.assert.strictEqual(setup, undefined);
89+
const stmt = db.prepare('INSERT INTO data (key, val) VALUES ($k, $v)');
90+
t.assert.strictEqual(stmt.setAllowUnknownNamedParameters(true), undefined);
91+
const params = { $a: 1, $b: 2, $k: 42, $y: 25, $v: 84, $z: 99 };
92+
t.assert.deepStrictEqual(
93+
stmt.run(params),
94+
{ changes: 1, lastInsertRowid: 1 },
95+
);
96+
t.assert.strictEqual(stmt.setAllowUnknownNamedParameters(false), undefined);
97+
t.assert.throws(() => {
98+
stmt.run(params);
99+
}, {
100+
code: 'ERR_INVALID_STATE',
101+
message: /Unknown named parameter '\$a'/,
102+
});
103+
});
104+
105+
test('throws when input is not a boolean', (t) => {
106+
const db = new DatabaseSync(':memory:');
107+
t.after(() => { db.close(); });
108+
const setup = db.exec(
109+
'CREATE TABLE data(key INTEGER PRIMARY KEY, val INTEGER) STRICT;'
110+
);
111+
t.assert.strictEqual(setup, undefined);
112+
const stmt = db.prepare('INSERT INTO data (key, val) VALUES ($k, $v)');
113+
t.assert.throws(() => {
114+
stmt.setAllowUnknownNamedParameters();
115+
}, {
116+
code: 'ERR_INVALID_ARG_TYPE',
117+
message: /The "enabled" argument must be a boolean/,
118+
});
119+
});
120+
});

0 commit comments

Comments
 (0)