Skip to content

Commit a06a068

Browse files
committed
sqlite: handle exception thrown in conflict handler
1 parent e6001b3 commit a06a068

File tree

3 files changed

+25
-2
lines changed

3 files changed

+25
-2
lines changed

doc/api/sqlite.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ added:
251251
`SQLITE_CHANGESET_DATA` or `SQLITE_CHANGESET_CONFLICT` conflicts).
252252
* `SQLITE_CHANGESET_ABORT`: Abort on conflict and roll back the database.
253253

254+
When an error is thrown in the conflict handler, applying the changeset is aborted and the database is rolled back.
255+
254256
**Default**: A function that returns `SQLITE_CHANGESET_ABORT`.
255257
* Returns: {boolean} Whether the changeset was applied succesfully without being aborted.
256258

src/node_sqlite.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "node_mem-inl.h"
1010
#include "sqlite3.h"
1111
#include "util-inl.h"
12+
#include "v8-exception.h"
1213

1314
#include <cinttypes>
1415

@@ -42,6 +43,7 @@ using v8::Number;
4243
using v8::Object;
4344
using v8::SideEffectType;
4445
using v8::String;
46+
using v8::TryCatch;
4547
using v8::Uint8Array;
4648
using v8::Value;
4749

@@ -795,9 +797,14 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
795797
Local<Function> conflictFunc = conflictValue.As<Function>();
796798
conflictCallback = [env, conflictFunc](int conflictType) -> int {
797799
Local<Value> argv[] = {Integer::New(env->isolate(), conflictType)};
800+
TryCatch try_catch(env->isolate());
798801
Local<Value> result =
799802
conflictFunc->Call(env->context(), Null(env->isolate()), 1, argv)
800-
.ToLocalChecked();
803+
.FromMaybe(Local<Value>());
804+
if (try_catch.HasCaught()) {
805+
try_catch.ReThrow();
806+
return SQLITE_CHANGESET_ABORT;
807+
}
801808
return result->Int32Value(env->context()).FromJust();
802809
};
803810
}

test/parallel/test-sqlite-session.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ suite('conflict resolution', () => {
323323
deepStrictEqual(t)(database2.prepare('SELECT key, value from data').all(), [{ key: 2, value: 'hello' }]);
324324
});
325325

326-
test("conflict resolution handler returns invalid value", (t) => {
326+
test('conflict resolution handler returns invalid value', (t) => {
327327
const { database2, changeset } = prepareConflict();
328328
t.assert.throws(() => {
329329
database2.applyChangeset(changeset, {
@@ -336,6 +336,20 @@ suite('conflict resolution', () => {
336336
message: 'bad parameter or other API misuse'
337337
});
338338
});
339+
340+
test('conflict resolution handler throws', (t) => {
341+
const { database2, changeset } = prepareConflict();
342+
t.assert.throws(() => {
343+
database2.applyChangeset(changeset, {
344+
onConflict: () => {
345+
throw new Error('some error');
346+
}
347+
});
348+
}, {
349+
name: 'Error',
350+
message: 'some error'
351+
});
352+
});
339353
});
340354

341355
test('database.createSession() - filter changes', (t) => {

0 commit comments

Comments
 (0)