Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
44 changes: 21 additions & 23 deletions src/node_sqlite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1763,21 +1763,21 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {

Local<Function> filterFunc = filterValue.As<Function>();

context.filterCallback = [env,
filterFunc](std::string_view item) -> bool {
// TODO(@jasnell): The use of ToLocalChecked here means that if
// the filter function throws an error the process will crash.
// The filterCallback should be updated to avoid the check and
// propagate the error correctly.
Local<Value> argv[] = {
String::NewFromUtf8(env->isolate(),
item.data(),
NewStringType::kNormal,
static_cast<int>(item.size()))
.ToLocalChecked()};
Local<Value> result =
filterFunc->Call(env->context(), Null(env->isolate()), 1, argv)
.ToLocalChecked();
context.filterCallback = [&](std::string_view item) -> bool {
Local<Value> argv[1];
if (!ToV8Value(env->context(), item, env->isolate())
.ToLocal(&argv[0])) {
db->SetIgnoreNextSQLiteError(true);
return false;
}

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());
};
}
Expand Down Expand Up @@ -2239,9 +2239,11 @@ Local<Value> StatementExecutionHelper::Get(Environment* env,
LocalVector<Name> keys(isolate);
keys.reserve(num_cols);
for (int i = 0; i < num_cols; ++i) {
MaybeLocal<Name> key = ColumnNameToName(env, stmt, i);
if (key.IsEmpty()) return Undefined(isolate);
keys.emplace_back(key.ToLocalChecked());
Local<Name> key;
if (!ColumnNameToName(env, stmt, i).ToLocal(&key)) {
return Undefined(isolate);
}
keys.emplace_back(key);
}

DCHECK_EQ(keys.size(), row_values.size());
Expand Down Expand Up @@ -2755,12 +2757,8 @@ BaseObjectPtr<StatementSync> SQLTagStore::PrepareStatement(

if (stmt == 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(
session->database_->connection_, *sql_utf8, -1, &s, 0);
session->database_->connection_, sql.c_str(), -1, &s, 0);

if (r != SQLITE_OK) {
THROW_ERR_SQLITE_ERROR(isolate, "Failed to prepare statement");
Expand Down
24 changes: 24 additions & 0 deletions test/parallel/test-sqlite-session.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: () => {
throw new Error('some error');
}
});
}, {
name: 'Error',
message: 'some error'
});
});

test('database.createSession() - filter changes', (t) => {
const database1 = new DatabaseSync(':memory:');
const database2 = new DatabaseSync(':memory:');
Expand Down
Loading