diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc index 80cd18cf60cb83..bcf03808033f8a 100644 --- a/src/node_sqlite.cc +++ b/src/node_sqlite.cc @@ -67,6 +67,54 @@ using v8::Value; } \ } while (0) +#define SQLITE_VALUE_TO_JS(from, isolate, use_big_int_args, result, ...) \ + do { \ + switch (sqlite3_##from##_type(__VA_ARGS__)) { \ + case SQLITE_INTEGER: { \ + sqlite3_int64 val = sqlite3_##from##_int64(__VA_ARGS__); \ + if ((use_big_int_args)) { \ + (result) = BigInt::New((isolate), val); \ + } else if (std::abs(val) <= kMaxSafeJsInteger) { \ + (result) = Number::New((isolate), val); \ + } else { \ + THROW_ERR_OUT_OF_RANGE((isolate), \ + "Value is too large to be represented as a " \ + "JavaScript number: %" PRId64, \ + val); \ + } \ + break; \ + } \ + case SQLITE_FLOAT: { \ + (result) = \ + Number::New((isolate), sqlite3_##from##_double(__VA_ARGS__)); \ + break; \ + } \ + case SQLITE_TEXT: { \ + const char* v = \ + reinterpret_cast(sqlite3_##from##_text(__VA_ARGS__)); \ + (result) = String::NewFromUtf8((isolate), v).As(); \ + break; \ + } \ + case SQLITE_NULL: { \ + (result) = Null((isolate)); \ + break; \ + } \ + case SQLITE_BLOB: { \ + size_t size = \ + static_cast(sqlite3_##from##_bytes(__VA_ARGS__)); \ + auto data = reinterpret_cast( \ + sqlite3_##from##_blob(__VA_ARGS__)); \ + auto store = ArrayBuffer::NewBackingStore((isolate), size); \ + memcpy(store->Data(), data, size); \ + auto ab = ArrayBuffer::New((isolate), std::move(store)); \ + (result) = Uint8Array::New(ab, 0, size); \ + break; \ + } \ + default: \ + UNREACHABLE("Bad SQLite value"); \ + } \ + } while (0) + inline MaybeLocal CreateSQLiteError(Isolate* isolate, const char* message) { Local js_msg; @@ -356,51 +404,13 @@ void UserDefinedFunction::xFunc(sqlite3_context* ctx, for (int i = 0; i < argc; ++i) { sqlite3_value* value = argv[i]; - MaybeLocal js_val; - - switch (sqlite3_value_type(value)) { - case SQLITE_INTEGER: { - sqlite3_int64 val = sqlite3_value_int64(value); - if (self->use_bigint_args_) { - js_val = BigInt::New(isolate, val); - } else if (std::abs(val) <= kMaxSafeJsInteger) { - js_val = Number::New(isolate, val); - } else { - // Ignore the SQLite error because a JavaScript exception is being - // thrown. - self->db_->SetIgnoreNextSQLiteError(true); - sqlite3_result_error(ctx, "", 0); - THROW_ERR_OUT_OF_RANGE(isolate, - "Value is too large to be represented as a " - "JavaScript number: %" PRId64, - val); - return; - } - break; - } - case SQLITE_FLOAT: - js_val = Number::New(isolate, sqlite3_value_double(value)); - break; - case SQLITE_TEXT: { - const char* v = - reinterpret_cast(sqlite3_value_text(value)); - js_val = String::NewFromUtf8(isolate, v).As(); - break; - } - case SQLITE_NULL: - js_val = Null(isolate); - break; - case SQLITE_BLOB: { - size_t size = static_cast(sqlite3_value_bytes(value)); - auto data = reinterpret_cast(sqlite3_value_blob(value)); - auto store = ArrayBuffer::NewBackingStore(isolate, size); - memcpy(store->Data(), data, size); - auto ab = ArrayBuffer::New(isolate, std::move(store)); - js_val = Uint8Array::New(ab, 0, size); - break; - } - default: - UNREACHABLE("Bad SQLite value"); + MaybeLocal js_val = MaybeLocal(); + SQLITE_VALUE_TO_JS(value, isolate, self->use_bigint_args_, js_val, value); + if (js_val.IsEmpty()) { + // Ignore the SQLite error because a JavaScript exception is pending. + self->db_->SetIgnoreNextSQLiteError(true); + sqlite3_result_error(ctx, "", 0); + return; } Local local; @@ -1511,45 +1521,11 @@ bool StatementSync::BindValue(const Local& value, const int index) { } MaybeLocal StatementSync::ColumnToValue(const int column) { - switch (sqlite3_column_type(statement_, column)) { - case SQLITE_INTEGER: { - sqlite3_int64 value = sqlite3_column_int64(statement_, column); - if (use_big_ints_) { - return BigInt::New(env()->isolate(), value); - } else if (std::abs(value) <= kMaxSafeJsInteger) { - return Number::New(env()->isolate(), value); - } else { - THROW_ERR_OUT_OF_RANGE(env()->isolate(), - "The value of column %d is too large to be " - "represented as a JavaScript number: %" PRId64, - column, - value); - return MaybeLocal(); - } - } - case SQLITE_FLOAT: - return Number::New(env()->isolate(), - sqlite3_column_double(statement_, column)); - case SQLITE_TEXT: { - const char* value = reinterpret_cast( - sqlite3_column_text(statement_, column)); - return String::NewFromUtf8(env()->isolate(), value).As(); - } - case SQLITE_NULL: - return Null(env()->isolate()); - case SQLITE_BLOB: { - size_t size = - static_cast(sqlite3_column_bytes(statement_, column)); - auto data = reinterpret_cast( - sqlite3_column_blob(statement_, column)); - auto store = ArrayBuffer::NewBackingStore(env()->isolate(), size); - memcpy(store->Data(), data, size); - auto ab = ArrayBuffer::New(env()->isolate(), std::move(store)); - return Uint8Array::New(ab, 0, size); - } - default: - UNREACHABLE("Bad SQLite column type"); - } + Isolate* isolate = env()->isolate(); + MaybeLocal js_val = MaybeLocal(); + SQLITE_VALUE_TO_JS( + column, isolate, use_big_ints_, js_val, statement_, column); + return js_val; } MaybeLocal StatementSync::ColumnNameToName(const int column) { diff --git a/test/parallel/test-sqlite-statement-sync.js b/test/parallel/test-sqlite-statement-sync.js index 7d17e73ebbd649..def28f02bd0d6c 100644 --- a/test/parallel/test-sqlite-statement-sync.js +++ b/test/parallel/test-sqlite-statement-sync.js @@ -282,7 +282,7 @@ suite('StatementSync.prototype.setReadBigInts()', () => { bad.get(); }, { code: 'ERR_OUT_OF_RANGE', - message: /^The value of column 0 is too large.*: 9007199254740992$/, + message: /^Value is too large to be represented as a JavaScript number: 9007199254740992$/, }); const good = db.prepare(`SELECT ${Number.MAX_SAFE_INTEGER} + 1`); good.setReadBigInts(true);