Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
sqlite: handle exception thrown in conflict handler
  • Loading branch information
louwers committed Dec 24, 2024
commit a06a068518fb6dc746ccca4a9d96b682ee93eae9
2 changes: 2 additions & 0 deletions doc/api/sqlite.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ added:
`SQLITE_CHANGESET_DATA` or `SQLITE_CHANGESET_CONFLICT` conflicts).
* `SQLITE_CHANGESET_ABORT`: Abort on conflict and roll back the database.

When an error is thrown in the conflict handler, applying the changeset is aborted and the database is rolled back.

**Default**: A function that returns `SQLITE_CHANGESET_ABORT`.
* Returns: {boolean} Whether the changeset was applied succesfully without being aborted.

Expand Down
9 changes: 8 additions & 1 deletion src/node_sqlite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "node_mem-inl.h"
#include "sqlite3.h"
#include "util-inl.h"
#include "v8-exception.h"
Comment thread
louwers marked this conversation as resolved.
Outdated
Comment thread
louwers marked this conversation as resolved.
Outdated

#include <cinttypes>

Expand Down Expand Up @@ -42,6 +43,7 @@ using v8::Number;
using v8::Object;
using v8::SideEffectType;
using v8::String;
using v8::TryCatch;
using v8::Uint8Array;
using v8::Value;

Expand Down Expand Up @@ -795,9 +797,14 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
Local<Function> conflictFunc = conflictValue.As<Function>();
conflictCallback = [env, conflictFunc](int conflictType) -> int {
Local<Value> argv[] = {Integer::New(env->isolate(), conflictType)};
TryCatch try_catch(env->isolate());
Local<Value> result =
conflictFunc->Call(env->context(), Null(env->isolate()), 1, argv)
.ToLocalChecked();
.FromMaybe(Local<Value>());
if (try_catch.HasCaught()) {
try_catch.ReThrow();
return SQLITE_CHANGESET_ABORT;
}
return result->Int32Value(env->context()).FromJust();
Comment thread
louwers marked this conversation as resolved.
};
Comment thread
louwers marked this conversation as resolved.
}
Expand Down
16 changes: 15 additions & 1 deletion test/parallel/test-sqlite-session.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ suite('conflict resolution', () => {
deepStrictEqual(t)(database2.prepare('SELECT key, value from data').all(), [{ key: 2, value: 'hello' }]);
});

test("conflict resolution handler returns invalid value", (t) => {
test('conflict resolution handler returns invalid value', (t) => {
const { database2, changeset } = prepareConflict();
t.assert.throws(() => {
database2.applyChangeset(changeset, {
Expand All @@ -336,6 +336,20 @@ suite('conflict resolution', () => {
message: 'bad parameter or other API misuse'
});
});

test('conflict resolution handler throws', (t) => {
const { database2, changeset } = prepareConflict();
t.assert.throws(() => {
database2.applyChangeset(changeset, {
onConflict: () => {
Comment thread
louwers marked this conversation as resolved.
throw new Error('some error');
}
});
}, {
name: 'Error',
message: 'some error'
});
});
});

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