From 3dceb918a111321138337df787108f1a6b8f8ca4 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 18 Apr 2024 13:47:47 +1000 Subject: [PATCH 1/2] add offset to error message --- somefile | 0 src/database.cc | 11 +++++++---- src/database.h | 1 + src/macros.h | 16 ++++++++++++++++ src/statement.cc | 7 ++++++- src/statement.h | 1 + test/database_fail.test.js | 11 +++++++++++ 7 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 somefile diff --git a/somefile b/somefile new file mode 100644 index 000000000..e69de29bb diff --git a/src/database.cc b/src/database.cc index d495ce98f..0aa779060 100644 --- a/src/database.cc +++ b/src/database.cc @@ -167,6 +167,7 @@ void Database::Work_Open(napi_env e, void* data) { if (baton->status != SQLITE_OK) { baton->message = std::string(sqlite3_errmsg(db->_handle)); + baton->offset = sqlite3_error_offset(db->_handle); sqlite3_close(db->_handle); db->_handle = NULL; } @@ -186,7 +187,7 @@ void Database::Work_AfterOpen(napi_env e, napi_status status, void* data) { Napi::Value argv[1]; if (baton->status != SQLITE_OK) { - EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception); + EXCEPTION_WITH_OFFSET(Napi::String::New(env, baton->message.c_str()), baton->status, baton->offset, exception); argv[0] = exception; } else { @@ -250,6 +251,7 @@ void Database::Work_Close(napi_env e, void* data) { if (baton->status != SQLITE_OK) { baton->message = std::string(sqlite3_errmsg(db->_handle)); + baton->offset = sqlite3_error_offset(db->_handle); } else { db->_handle = NULL; @@ -269,7 +271,7 @@ void Database::Work_AfterClose(napi_env e, napi_status status, void* data) { Napi::Value argv[1]; if (baton->status != SQLITE_OK) { - EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception); + EXCEPTION_WITH_OFFSET(Napi::String::New(env, baton->message.c_str()), baton->status, baton->offset, exception); argv[0] = exception; } else { @@ -592,6 +594,7 @@ void Database::Work_Exec(napi_env e, void* data) { if (baton->status != SQLITE_OK && message != NULL) { baton->message = std::string(message); + baton->offset = sqlite3_error_offset(baton->db->_handle); sqlite3_free(message); } } @@ -608,7 +611,7 @@ void Database::Work_AfterExec(napi_env e, napi_status status, void* data) { Napi::Function cb = baton->callback.Value(); if (baton->status != SQLITE_OK) { - EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception); + EXCEPTION_WITH_OFFSET(Napi::String::New(env, baton->message.c_str()), baton->status, baton->offset, exception); if (IS_FUNCTION(cb)) { Napi::Value argv[] = { exception }; @@ -716,7 +719,7 @@ void Database::Work_AfterLoadExtension(napi_env e, napi_status status, void* dat Napi::Function cb = baton->callback.Value(); if (baton->status != SQLITE_OK) { - EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception); + EXCEPTION_WITH_OFFSET(Napi::String::New(env, baton->message.c_str()), baton->status, baton->offset, exception); if (IS_FUNCTION(cb)) { Napi::Value argv[] = { exception }; diff --git a/src/database.h b/src/database.h index 8ffd300d2..921e80957 100644 --- a/src/database.h +++ b/src/database.h @@ -45,6 +45,7 @@ class Database : public Napi::ObjectWrap { Database* db; Napi::FunctionReference callback; int status; + int offset; std::string message; Baton(Database* db_, Napi::Function cb_) : diff --git a/src/macros.h b/src/macros.h index 3bcde83c6..6ab1ab966 100644 --- a/src/macros.h +++ b/src/macros.h @@ -113,6 +113,22 @@ inline bool OtherIsInt(Napi::Number source) { (name ##_obj).Set( Napi::String::New(env, "code"), \ Napi::String::New(env, sqlite_code_string(errno))); +#define EXCEPTION_WITH_OFFSET(msg, errno, offset, name) \ + Napi::Value name = Napi::Error::New(env, \ + StringConcat( \ + StringConcat( \ + Napi::String::New(env, sqlite_code_string(errno)), \ + Napi::String::New(env, ": ") \ + ), \ + (msg) \ + ).Utf8Value() \ + ).Value(); \ + Napi::Object name ##_obj = name.As(); \ + (name ##_obj).Set( Napi::String::New(env, "errno"), Napi::Number::New(env, errno)); \ + (name ##_obj).Set( Napi::String::New(env, "offset"), Napi::Number::New(env, offset)); \ + (name ##_obj).Set( Napi::String::New(env, "code"), \ + Napi::String::New(env, sqlite_code_string(errno))); + #define EMIT_EVENT(obj, argc, argv) \ TRY_CATCH_CALL((obj), \ diff --git a/src/statement.cc b/src/statement.cc index fc49b90f1..fc9f57860 100644 --- a/src/statement.cc +++ b/src/statement.cc @@ -73,7 +73,7 @@ template void Statement::Error(T* baton) { // Fail hard on logic errors. assert(stmt->status != 0); - EXCEPTION(Napi::String::New(env, stmt->message.c_str()), stmt->status, exception); + EXCEPTION_WITH_OFFSET(Napi::String::New(env, stmt->message.c_str()), stmt->status, stmt->offset, exception); Napi::Function cb = baton->callback.Value(); @@ -146,6 +146,7 @@ void Statement::Work_Prepare(napi_env e, void* data) { if (stmt->status != SQLITE_OK) { stmt->message = std::string(sqlite3_errmsg(baton->db->_handle)); + stmt->offset = sqlite3_error_offset(baton->db->_handle); stmt->_handle = NULL; } @@ -412,6 +413,7 @@ void Statement::Work_Get(napi_env e, void* data) { if (!(stmt->status == SQLITE_ROW || stmt->status == SQLITE_DONE)) { stmt->message = std::string(sqlite3_errmsg(stmt->db->_handle)); + stmt->offset = sqlite3_error_offset(stmt->db->_handle); } } @@ -488,6 +490,7 @@ void Statement::Work_Run(napi_env e, void* data) { if (!(stmt->status == SQLITE_ROW || stmt->status == SQLITE_DONE)) { stmt->message = std::string(sqlite3_errmsg(stmt->db->_handle)); + stmt->offset = sqlite3_error_offset(stmt->db->_handle); } else { baton->inserted_id = sqlite3_last_insert_rowid(stmt->db->_handle); @@ -562,6 +565,7 @@ void Statement::Work_All(napi_env e, void* data) { if (stmt->status != SQLITE_DONE) { stmt->message = std::string(sqlite3_errmsg(stmt->db->_handle)); + stmt->offset = sqlite3_error_offset(stmt->db->_handle); } } @@ -671,6 +675,7 @@ void Statement::Work_Each(napi_env e, void* data) { else { if (stmt->status != SQLITE_DONE) { stmt->message = std::string(sqlite3_errmsg(stmt->db->_handle)); + stmt->offset = sqlite3_error_offset(stmt->db->_handle); } sqlite3_mutex_leave(mtx); break; diff --git a/src/statement.h b/src/statement.h index c522c0fdf..925621445 100644 --- a/src/statement.h +++ b/src/statement.h @@ -237,6 +237,7 @@ class Statement : public Napi::ObjectWrap { std::queue queue; std::string message; + int offset = -1; }; } diff --git a/test/database_fail.test.js b/test/database_fail.test.js index 8b936769e..a21503284 100644 --- a/test/database_fail.test.js +++ b/test/database_fail.test.js @@ -30,6 +30,17 @@ describe('error handling', function() { }); }); + it('should should provide an offset in the error object', function(done) { + db.get('SELECT id, txt ROM foo', function(err, row) { + if (err) { + assert.equal(err.offset, 'SELECT id, txt ROM '.length); + done(); + } else { + done(new Error('Completed query without error, but expected error')); + } + }); + }); + it('Database#all prepare fail', function(done) { db.all('SELECT id, txt FROM foo', function(err, row) { if (err) { From 86d8a612c04dc391315a9e7f964f24bc35e31bd3 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 18 Apr 2024 13:49:43 +1000 Subject: [PATCH 2/2] mistake --- test/database_fail.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/database_fail.test.js b/test/database_fail.test.js index a21503284..50f3dbb00 100644 --- a/test/database_fail.test.js +++ b/test/database_fail.test.js @@ -30,7 +30,7 @@ describe('error handling', function() { }); }); - it('should should provide an offset in the error object', function(done) { + it('should provide an offset in the error object', function(done) { db.get('SELECT id, txt ROM foo', function(err, row) { if (err) { assert.equal(err.offset, 'SELECT id, txt ROM '.length);