| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent c412b18 commit d949222
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1763,21 +1763,27 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) { | |||
| 1763 | 1763 | ||
| 1764 | 1764 | Local<Function> filterFunc = filterValue.As<Function>(); | |
| 1765 | 1765 | ||
| 1766 | - context.filterCallback = [env, | ||
| 1767 | - filterFunc](std::string_view item) -> bool { | ||
| 1768 | - // TODO(@jasnell): The use of ToLocalChecked here means that if | ||
| 1769 | - // the filter function throws an error the process will crash. | ||
| 1770 | - // The filterCallback should be updated to avoid the check and | ||
| 1771 | - // propagate the error correctly. | ||
| 1772 | - Local<Value> argv[] = { | ||
| 1773 | - String::NewFromUtf8(env->isolate(), | ||
| 1774 | - item.data(), | ||
| 1775 | - NewStringType::kNormal, | ||
| 1776 | - static_cast<int>(item.size())) | ||
| 1777 | - .ToLocalChecked()}; | ||
| 1778 | - Local<Value> result = | ||
| 1779 | - filterFunc->Call(env->context(), Null(env->isolate()), 1, argv) | ||
| 1780 | - .ToLocalChecked(); | ||
| 1766 | + context.filterCallback = [&](std::string_view item) -> bool { | ||
| 1767 | + // If there was an error in the previous call to the filter's | ||
| 1768 | + // callback, we skip calling it again. | ||
| 1769 | + if (db->ignore_next_sqlite_error_) { | ||
| 1770 | + return false; | ||
| 1771 | + } | ||
| 1772 | + | ||
| 1773 | + Local<Value> argv[1]; | ||
| 1774 | + if (!ToV8Value(env->context(), item, env->isolate()) | ||
| 1775 | + .ToLocal(&argv[0])) { | ||
| 1776 | + db->SetIgnoreNextSQLiteError(true); | ||
| 1777 | + return false; | ||
| 1778 | + } | ||
| 1779 | + | ||
| 1780 | + Local<Value> result; | ||
| 1781 | + if (!filterFunc->Call(env->context(), Null(env->isolate()), 1, argv) | ||
| 1782 | + .ToLocal(&result)) { | ||
| 1783 | + db->SetIgnoreNextSQLiteError(true); | ||
| 1784 | + return false; | ||
| 1785 | + } | ||
| 1786 | + | ||
| 1781 | 1787 | return result->BooleanValue(env->isolate()); | |
| 1782 | 1788 | }; | |
| 1783 | 1789 | } | |
@@ -2239,9 +2245,11 @@ Local<Value> StatementExecutionHelper::Get(Environment* env, | |||
| 2239 | 2245 | LocalVector<Name> keys(isolate); | |
| 2240 | 2246 | keys.reserve(num_cols); | |
| 2241 | 2247 | for (int i = 0; i < num_cols; ++i) { | |
| 2242 | - MaybeLocal<Name> key = ColumnNameToName(env, stmt, i); | ||
| 2243 | - if (key.IsEmpty()) return Undefined(isolate); | ||
| 2244 | - keys.emplace_back(key.ToLocalChecked()); | ||
| 2248 | + Local<Name> key; | ||
| 2249 | + if (!ColumnNameToName(env, stmt, i).ToLocal(&key)) { | ||
| 2250 | + return Undefined(isolate); | ||
| 2251 | + } | ||
| 2252 | + keys.emplace_back(key); | ||
| 2245 | 2253 | } | |
| 2246 | 2254 | ||
| 2247 | 2255 | DCHECK_EQ(keys.size(), row_values.size()); | |
@@ -2755,12 +2763,8 @@ BaseObjectPtr<StatementSync> SQLTagStore::PrepareStatement( | |||
| 2755 | 2763 | ||
| 2756 | 2764 | if (stmt == nullptr) { | |
| 2757 | 2765 | sqlite3_stmt* s = nullptr; | |
| 2758 | - Local<String> sql_str = | ||
| 2759 | - String::NewFromUtf8(isolate, sql.c_str()).ToLocalChecked(); | ||
| 2760 | - Utf8Value sql_utf8(isolate, sql_str); | ||
| 2761 | - | ||
| 2762 | 2766 | int r = sqlite3_prepare_v2( | |
| 2763 | - session->database_->connection_, *sql_utf8, -1, &s, 0); | ||
| 2767 | + session->database_->connection_, sql.c_str(), -1, &s, 0); | ||
| 2764 | 2768 | ||
| 2765 | 2769 | if (r != SQLITE_OK) { | |
| 2766 | 2770 | THROW_ERR_SQLITE_ERROR(isolate, "Failed to prepare statement"); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -366,6 +366,30 @@ suite('conflict resolution', () => { | |||
| 366 | 366 | }); | |
| 367 | 367 | }); | |
| 368 | 368 | ||
| 369 | + test('filter handler throws', (t) => { | ||
| 370 | + const database1 = new DatabaseSync(':memory:'); | ||
| 371 | + const database2 = new DatabaseSync(':memory:'); | ||
| 372 | + const createTableSql = 'CREATE TABLE data1(key INTEGER PRIMARY KEY); CREATE TABLE data2(key INTEGER PRIMARY KEY);'; | ||
| 373 | + database1.exec(createTableSql); | ||
| 374 | + database2.exec(createTableSql); | ||
| 375 | + | ||
| 376 | + const session = database1.createSession(); | ||
| 377 | + | ||
| 378 | + database1.exec('INSERT INTO data1 (key) VALUES (1), (2), (3)'); | ||
| 379 | + database1.exec('INSERT INTO data2 (key) VALUES (1), (2), (3), (4), (5)'); | ||
| 380 | + | ||
| 381 | + t.assert.throws(() => { | ||
| 382 | + database2.applyChangeset(session.changeset(), { | ||
| 383 | + filter: (tableName) => { | ||
| 384 | + throw new Error(`Error filtering table ${tableName}`); | ||
| 385 | + } | ||
| 386 | + }); | ||
| 387 | + }, { | ||
| 388 | + name: 'Error', | ||
| 389 | + message: 'Error filtering table data1' | ||
| 390 | + }); | ||
| 391 | + }); | ||
| 392 | + | ||
| 369 | 393 | test('database.createSession() - filter changes', (t) => { | |
| 370 | 394 | const database1 = new DatabaseSync(':memory:'); | |
| 371 | 395 | const database2 = new DatabaseSync(':memory:'); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments