mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 12:20:27 +01:00
sqlite: replace ToLocalChecked and improve filter error handling
PR-URL: https://github.com/nodejs/node/pull/60028 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
075936b413
commit
413693481f
|
|
@ -1763,21 +1763,27 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
|
||||||
Local<Function> filterFunc = filterValue.As<Function>();
|
Local<Function> filterFunc = filterValue.As<Function>();
|
||||||
|
|
||||||
context.filterCallback = [env,
|
context.filterCallback = [&](std::string_view item) -> bool {
|
||||||
filterFunc](std::string_view item) -> bool {
|
// If there was an error in the previous call to the filter's
|
||||||
// TODO(@jasnell): The use of ToLocalChecked here means that if
|
// callback, we skip calling it again.
|
||||||
// the filter function throws an error the process will crash.
|
if (db->ignore_next_sqlite_error_) {
|
||||||
// The filterCallback should be updated to avoid the check and
|
return false;
|
||||||
// propagate the error correctly.
|
}
|
||||||
Local<Value> argv[] = {
|
|
||||||
String::NewFromUtf8(env->isolate(),
|
Local<Value> argv[1];
|
||||||
item.data(),
|
if (!ToV8Value(env->context(), item, env->isolate())
|
||||||
NewStringType::kNormal,
|
.ToLocal(&argv[0])) {
|
||||||
static_cast<int>(item.size()))
|
db->SetIgnoreNextSQLiteError(true);
|
||||||
.ToLocalChecked()};
|
return false;
|
||||||
Local<Value> result =
|
}
|
||||||
filterFunc->Call(env->context(), Null(env->isolate()), 1, argv)
|
|
||||||
.ToLocalChecked();
|
Local<Value> result;
|
||||||
|
if (!filterFunc->Call(env->context(), Null(env->isolate()), 1, argv)
|
||||||
|
.ToLocal(&result)) {
|
||||||
|
db->SetIgnoreNextSQLiteError(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return result->BooleanValue(env->isolate());
|
return result->BooleanValue(env->isolate());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -2239,9 +2245,11 @@ Local<Value> StatementExecutionHelper::Get(Environment* env,
|
||||||
LocalVector<Name> keys(isolate);
|
LocalVector<Name> keys(isolate);
|
||||||
keys.reserve(num_cols);
|
keys.reserve(num_cols);
|
||||||
for (int i = 0; i < num_cols; ++i) {
|
for (int i = 0; i < num_cols; ++i) {
|
||||||
MaybeLocal<Name> key = ColumnNameToName(env, stmt, i);
|
Local<Name> key;
|
||||||
if (key.IsEmpty()) return Undefined(isolate);
|
if (!ColumnNameToName(env, stmt, i).ToLocal(&key)) {
|
||||||
keys.emplace_back(key.ToLocalChecked());
|
return Undefined(isolate);
|
||||||
|
}
|
||||||
|
keys.emplace_back(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
DCHECK_EQ(keys.size(), row_values.size());
|
DCHECK_EQ(keys.size(), row_values.size());
|
||||||
|
|
@ -2755,12 +2763,8 @@ BaseObjectPtr<StatementSync> SQLTagStore::PrepareStatement(
|
||||||
|
|
||||||
if (stmt == nullptr) {
|
if (stmt == nullptr) {
|
||||||
sqlite3_stmt* s = nullptr;
|
sqlite3_stmt* s = nullptr;
|
||||||
Local<String> sql_str =
|
|
||||||
String::NewFromUtf8(isolate, sql.c_str()).ToLocalChecked();
|
|
||||||
Utf8Value sql_utf8(isolate, sql_str);
|
|
||||||
|
|
||||||
int r = sqlite3_prepare_v2(
|
int r = sqlite3_prepare_v2(
|
||||||
session->database_->connection_, *sql_utf8, -1, &s, 0);
|
session->database_->connection_, sql.c_str(), -1, &s, 0);
|
||||||
|
|
||||||
if (r != SQLITE_OK) {
|
if (r != SQLITE_OK) {
|
||||||
THROW_ERR_SQLITE_ERROR(isolate, "Failed to prepare statement");
|
THROW_ERR_SQLITE_ERROR(isolate, "Failed to prepare statement");
|
||||||
|
|
|
||||||
|
|
@ -366,6 +366,30 @@ suite('conflict resolution', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('filter handler throws', (t) => {
|
||||||
|
const database1 = new DatabaseSync(':memory:');
|
||||||
|
const database2 = new DatabaseSync(':memory:');
|
||||||
|
const createTableSql = 'CREATE TABLE data1(key INTEGER PRIMARY KEY); CREATE TABLE data2(key INTEGER PRIMARY KEY);';
|
||||||
|
database1.exec(createTableSql);
|
||||||
|
database2.exec(createTableSql);
|
||||||
|
|
||||||
|
const session = database1.createSession();
|
||||||
|
|
||||||
|
database1.exec('INSERT INTO data1 (key) VALUES (1), (2), (3)');
|
||||||
|
database1.exec('INSERT INTO data2 (key) VALUES (1), (2), (3), (4), (5)');
|
||||||
|
|
||||||
|
t.assert.throws(() => {
|
||||||
|
database2.applyChangeset(session.changeset(), {
|
||||||
|
filter: (tableName) => {
|
||||||
|
throw new Error(`Error filtering table ${tableName}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, {
|
||||||
|
name: 'Error',
|
||||||
|
message: 'Error filtering table data1'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('database.createSession() - filter changes', (t) => {
|
test('database.createSession() - filter changes', (t) => {
|
||||||
const database1 = new DatabaseSync(':memory:');
|
const database1 = new DatabaseSync(':memory:');
|
||||||
const database2 = new DatabaseSync(':memory:');
|
const database2 = new DatabaseSync(':memory:');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user