Skip to content

Commit eaf7eba

Browse files
geeksilva97JonasBa
authored andcommitted
sqlite,src: refactor sqlite value conversion
PR-URL: nodejs#57571 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
1 parent fcaca23 commit eaf7eba

File tree

2 files changed

+61
-85
lines changed

2 files changed

+61
-85
lines changed

src/node_sqlite.cc

+60-84
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,54 @@ using v8::Value;
6666
} \
6767
} while (0)
6868

69+
#define SQLITE_VALUE_TO_JS(from, isolate, use_big_int_args, result, ...) \
70+
do { \
71+
switch (sqlite3_##from##_type(__VA_ARGS__)) { \
72+
case SQLITE_INTEGER: { \
73+
sqlite3_int64 val = sqlite3_##from##_int64(__VA_ARGS__); \
74+
if ((use_big_int_args)) { \
75+
(result) = BigInt::New((isolate), val); \
76+
} else if (std::abs(val) <= kMaxSafeJsInteger) { \
77+
(result) = Number::New((isolate), val); \
78+
} else { \
79+
THROW_ERR_OUT_OF_RANGE((isolate), \
80+
"Value is too large to be represented as a " \
81+
"JavaScript number: %" PRId64, \
82+
val); \
83+
} \
84+
break; \
85+
} \
86+
case SQLITE_FLOAT: { \
87+
(result) = \
88+
Number::New((isolate), sqlite3_##from##_double(__VA_ARGS__)); \
89+
break; \
90+
} \
91+
case SQLITE_TEXT: { \
92+
const char* v = \
93+
reinterpret_cast<const char*>(sqlite3_##from##_text(__VA_ARGS__)); \
94+
(result) = String::NewFromUtf8((isolate), v).As<Value>(); \
95+
break; \
96+
} \
97+
case SQLITE_NULL: { \
98+
(result) = Null((isolate)); \
99+
break; \
100+
} \
101+
case SQLITE_BLOB: { \
102+
size_t size = \
103+
static_cast<size_t>(sqlite3_##from##_bytes(__VA_ARGS__)); \
104+
auto data = reinterpret_cast<const uint8_t*>( \
105+
sqlite3_##from##_blob(__VA_ARGS__)); \
106+
auto store = ArrayBuffer::NewBackingStore((isolate), size); \
107+
memcpy(store->Data(), data, size); \
108+
auto ab = ArrayBuffer::New((isolate), std::move(store)); \
109+
(result) = Uint8Array::New(ab, 0, size); \
110+
break; \
111+
} \
112+
default: \
113+
UNREACHABLE("Bad SQLite value"); \
114+
} \
115+
} while (0)
116+
69117
inline MaybeLocal<Object> CreateSQLiteError(Isolate* isolate,
70118
const char* message) {
71119
Local<String> js_msg;
@@ -355,51 +403,13 @@ void UserDefinedFunction::xFunc(sqlite3_context* ctx,
355403

356404
for (int i = 0; i < argc; ++i) {
357405
sqlite3_value* value = argv[i];
358-
MaybeLocal<Value> js_val;
359-
360-
switch (sqlite3_value_type(value)) {
361-
case SQLITE_INTEGER: {
362-
sqlite3_int64 val = sqlite3_value_int64(value);
363-
if (self->use_bigint_args_) {
364-
js_val = BigInt::New(isolate, val);
365-
} else if (std::abs(val) <= kMaxSafeJsInteger) {
366-
js_val = Number::New(isolate, val);
367-
} else {
368-
// Ignore the SQLite error because a JavaScript exception is being
369-
// thrown.
370-
self->db_->SetIgnoreNextSQLiteError(true);
371-
sqlite3_result_error(ctx, "", 0);
372-
THROW_ERR_OUT_OF_RANGE(isolate,
373-
"Value is too large to be represented as a "
374-
"JavaScript number: %" PRId64,
375-
val);
376-
return;
377-
}
378-
break;
379-
}
380-
case SQLITE_FLOAT:
381-
js_val = Number::New(isolate, sqlite3_value_double(value));
382-
break;
383-
case SQLITE_TEXT: {
384-
const char* v =
385-
reinterpret_cast<const char*>(sqlite3_value_text(value));
386-
js_val = String::NewFromUtf8(isolate, v).As<Value>();
387-
break;
388-
}
389-
case SQLITE_NULL:
390-
js_val = Null(isolate);
391-
break;
392-
case SQLITE_BLOB: {
393-
size_t size = static_cast<size_t>(sqlite3_value_bytes(value));
394-
auto data = reinterpret_cast<const uint8_t*>(sqlite3_value_blob(value));
395-
auto store = ArrayBuffer::NewBackingStore(isolate, size);
396-
memcpy(store->Data(), data, size);
397-
auto ab = ArrayBuffer::New(isolate, std::move(store));
398-
js_val = Uint8Array::New(ab, 0, size);
399-
break;
400-
}
401-
default:
402-
UNREACHABLE("Bad SQLite value");
406+
MaybeLocal<Value> js_val = MaybeLocal<Value>();
407+
SQLITE_VALUE_TO_JS(value, isolate, self->use_bigint_args_, js_val, value);
408+
if (js_val.IsEmpty()) {
409+
// Ignore the SQLite error because a JavaScript exception is pending.
410+
self->db_->SetIgnoreNextSQLiteError(true);
411+
sqlite3_result_error(ctx, "", 0);
412+
return;
403413
}
404414

405415
Local<Value> local;
@@ -1521,45 +1531,11 @@ bool StatementSync::BindValue(const Local<Value>& value, const int index) {
15211531
}
15221532

15231533
MaybeLocal<Value> StatementSync::ColumnToValue(const int column) {
1524-
switch (sqlite3_column_type(statement_, column)) {
1525-
case SQLITE_INTEGER: {
1526-
sqlite3_int64 value = sqlite3_column_int64(statement_, column);
1527-
if (use_big_ints_) {
1528-
return BigInt::New(env()->isolate(), value);
1529-
} else if (std::abs(value) <= kMaxSafeJsInteger) {
1530-
return Number::New(env()->isolate(), value);
1531-
} else {
1532-
THROW_ERR_OUT_OF_RANGE(env()->isolate(),
1533-
"The value of column %d is too large to be "
1534-
"represented as a JavaScript number: %" PRId64,
1535-
column,
1536-
value);
1537-
return MaybeLocal<Value>();
1538-
}
1539-
}
1540-
case SQLITE_FLOAT:
1541-
return Number::New(env()->isolate(),
1542-
sqlite3_column_double(statement_, column));
1543-
case SQLITE_TEXT: {
1544-
const char* value = reinterpret_cast<const char*>(
1545-
sqlite3_column_text(statement_, column));
1546-
return String::NewFromUtf8(env()->isolate(), value).As<Value>();
1547-
}
1548-
case SQLITE_NULL:
1549-
return Null(env()->isolate());
1550-
case SQLITE_BLOB: {
1551-
size_t size =
1552-
static_cast<size_t>(sqlite3_column_bytes(statement_, column));
1553-
auto data = reinterpret_cast<const uint8_t*>(
1554-
sqlite3_column_blob(statement_, column));
1555-
auto store = ArrayBuffer::NewBackingStore(env()->isolate(), size);
1556-
memcpy(store->Data(), data, size);
1557-
auto ab = ArrayBuffer::New(env()->isolate(), std::move(store));
1558-
return Uint8Array::New(ab, 0, size);
1559-
}
1560-
default:
1561-
UNREACHABLE("Bad SQLite column type");
1562-
}
1534+
Isolate* isolate = env()->isolate();
1535+
MaybeLocal<Value> js_val = MaybeLocal<Value>();
1536+
SQLITE_VALUE_TO_JS(
1537+
column, isolate, use_big_ints_, js_val, statement_, column);
1538+
return js_val;
15631539
}
15641540

15651541
MaybeLocal<Name> StatementSync::ColumnNameToName(const int column) {

test/parallel/test-sqlite-statement-sync.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ suite('StatementSync.prototype.setReadBigInts()', () => {
332332
bad.get();
333333
}, {
334334
code: 'ERR_OUT_OF_RANGE',
335-
message: /^The value of column 0 is too large.*: 9007199254740992$/,
335+
message: /^Value is too large to be represented as a JavaScript number: 9007199254740992$/,
336336
});
337337
const good = db.prepare(`SELECT ${Number.MAX_SAFE_INTEGER} + 1`);
338338
good.setReadBigInts(true);

0 commit comments

Comments
 (0)