Skip to content

Commit 71a8a57

Browse files
committed
sqlite: improve error reporting for prepared statements in SQLTagStore
Fixes: #60198
1 parent d54e6ae commit 71a8a57

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

src/env_properties.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@
162162
V(errno_string, "errno") \
163163
V(error_string, "error") \
164164
V(errstr_string, "errstr") \
165+
V(errmsg_string, "errmsg") \
165166
V(events_waiting, "eventsWaiting") \
166167
V(events, "events") \
167168
V(exclusive_string, "exclusive") \

src/node_sqlite.cc

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,35 @@ inline MaybeLocal<Object> CreateSQLiteError(Isolate* isolate, sqlite3* db) {
188188
return e;
189189
}
190190

191+
inline MaybeLocal<Object> CreateSQLiteError(Isolate* isolate,
192+
sqlite3* db,
193+
const char* message) {
194+
int errcode = sqlite3_extended_errcode(db);
195+
const char* errstr = sqlite3_errstr(errcode);
196+
const char* errmsg = sqlite3_errmsg(db);
197+
Local<String> js_errstr;
198+
Local<String> js_errmsg;
199+
Local<Object> e;
200+
if (!String::NewFromUtf8(isolate, errstr).ToLocal(&js_errmsg) ||
201+
!String::NewFromUtf8(isolate, errmsg).ToLocal(&js_errstr) ||
202+
!CreateSQLiteError(isolate, message).ToLocal(&e) ||
203+
e->Set(isolate->GetCurrentContext(),
204+
Environment::GetCurrent(isolate)->errcode_string(),
205+
Integer::New(isolate, errcode))
206+
.IsNothing() ||
207+
e->Set(isolate->GetCurrentContext(),
208+
Environment::GetCurrent(isolate)->errstr_string(),
209+
js_errstr)
210+
.IsNothing() ||
211+
e->Set(isolate->GetCurrentContext(),
212+
Environment::GetCurrent(isolate)->errmsg_string(),
213+
js_errmsg)
214+
.IsNothing()) {
215+
return MaybeLocal<Object>();
216+
}
217+
return e;
218+
}
219+
191220
void JSValueToSQLiteResult(Isolate* isolate,
192221
sqlite3_context* ctx,
193222
Local<Value> value) {
@@ -241,6 +270,20 @@ inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate, const char* message) {
241270
}
242271
}
243272

273+
inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate,
274+
DatabaseSync* db,
275+
const char* message) {
276+
if (db->ShouldIgnoreSQLiteError()) {
277+
db->SetIgnoreNextSQLiteError(false);
278+
return;
279+
}
280+
281+
Local<Object> e;
282+
if (CreateSQLiteError(isolate, db->Connection(), message).ToLocal(&e)) {
283+
isolate->ThrowException(e);
284+
}
285+
}
286+
244287
inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate, int errcode) {
245288
const char* errstr = sqlite3_errstr(errcode);
246289

@@ -2906,7 +2949,8 @@ BaseObjectPtr<StatementSync> SQLTagStore::PrepareStatement(
29062949
session->database_->connection_, sql.data(), sql.size(), &s, 0);
29072950

29082951
if (r != SQLITE_OK) {
2909-
THROW_ERR_SQLITE_ERROR(isolate, "Failed to prepare statement");
2952+
THROW_ERR_SQLITE_ERROR(
2953+
isolate, session->database_.get(), "Failed to prepare statement");
29102954
sqlite3_finalize(s);
29112955
return BaseObjectPtr<StatementSync>();
29122956
}

test/parallel/test-sqlite-template-tag.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,16 @@ test('TagStore capacity, size, and clear', () => {
100100
test('sql.db returns the associated DatabaseSync instance', () => {
101101
assert.strictEqual(sql.db, db);
102102
});
103+
104+
test('failed prepares throw', () => {
105+
assert.throws(() => {
106+
sql.all`SELECT * FROM does_not_exist`; // eslint-disable-line no-unused-expressions
107+
}, {
108+
name: 'Error',
109+
message: 'Failed to prepare statement',
110+
code: 'ERR_SQLITE_ERROR',
111+
errcode: 1,
112+
errstr: 'no such table: does_not_exist',
113+
errmsg: 'SQL logic error'
114+
});
115+
});

0 commit comments

Comments
 (0)