sqlite,src: refactor sqlite value conversion
PR-URL: https://github.com/nodejs/node/pull/57571 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
parent
771b6829e6
commit
8360ce2abf
@ -66,6 +66,54 @@ using v8::Value;
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} 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<const char*>(sqlite3_##from##_text(__VA_ARGS__)); \
|
||||||
|
(result) = String::NewFromUtf8((isolate), v).As<Value>(); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
case SQLITE_NULL: { \
|
||||||
|
(result) = Null((isolate)); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
case SQLITE_BLOB: { \
|
||||||
|
size_t size = \
|
||||||
|
static_cast<size_t>(sqlite3_##from##_bytes(__VA_ARGS__)); \
|
||||||
|
auto data = reinterpret_cast<const uint8_t*>( \
|
||||||
|
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<Object> CreateSQLiteError(Isolate* isolate,
|
inline MaybeLocal<Object> CreateSQLiteError(Isolate* isolate,
|
||||||
const char* message) {
|
const char* message) {
|
||||||
Local<String> js_msg;
|
Local<String> js_msg;
|
||||||
@ -355,51 +403,13 @@ void UserDefinedFunction::xFunc(sqlite3_context* ctx,
|
|||||||
|
|
||||||
for (int i = 0; i < argc; ++i) {
|
for (int i = 0; i < argc; ++i) {
|
||||||
sqlite3_value* value = argv[i];
|
sqlite3_value* value = argv[i];
|
||||||
MaybeLocal<Value> js_val;
|
MaybeLocal<Value> js_val = MaybeLocal<Value>();
|
||||||
|
SQLITE_VALUE_TO_JS(value, isolate, self->use_bigint_args_, js_val, value);
|
||||||
switch (sqlite3_value_type(value)) {
|
if (js_val.IsEmpty()) {
|
||||||
case SQLITE_INTEGER: {
|
// Ignore the SQLite error because a JavaScript exception is pending.
|
||||||
sqlite3_int64 val = sqlite3_value_int64(value);
|
self->db_->SetIgnoreNextSQLiteError(true);
|
||||||
if (self->use_bigint_args_) {
|
sqlite3_result_error(ctx, "", 0);
|
||||||
js_val = BigInt::New(isolate, val);
|
return;
|
||||||
} 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<const char*>(sqlite3_value_text(value));
|
|
||||||
js_val = String::NewFromUtf8(isolate, v).As<Value>();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SQLITE_NULL:
|
|
||||||
js_val = Null(isolate);
|
|
||||||
break;
|
|
||||||
case SQLITE_BLOB: {
|
|
||||||
size_t size = static_cast<size_t>(sqlite3_value_bytes(value));
|
|
||||||
auto data = reinterpret_cast<const uint8_t*>(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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<Value> local;
|
Local<Value> local;
|
||||||
@ -1521,45 +1531,11 @@ bool StatementSync::BindValue(const Local<Value>& value, const int index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MaybeLocal<Value> StatementSync::ColumnToValue(const int column) {
|
MaybeLocal<Value> StatementSync::ColumnToValue(const int column) {
|
||||||
switch (sqlite3_column_type(statement_, column)) {
|
Isolate* isolate = env()->isolate();
|
||||||
case SQLITE_INTEGER: {
|
MaybeLocal<Value> js_val = MaybeLocal<Value>();
|
||||||
sqlite3_int64 value = sqlite3_column_int64(statement_, column);
|
SQLITE_VALUE_TO_JS(
|
||||||
if (use_big_ints_) {
|
column, isolate, use_big_ints_, js_val, statement_, column);
|
||||||
return BigInt::New(env()->isolate(), value);
|
return js_val;
|
||||||
} 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<Value>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case SQLITE_FLOAT:
|
|
||||||
return Number::New(env()->isolate(),
|
|
||||||
sqlite3_column_double(statement_, column));
|
|
||||||
case SQLITE_TEXT: {
|
|
||||||
const char* value = reinterpret_cast<const char*>(
|
|
||||||
sqlite3_column_text(statement_, column));
|
|
||||||
return String::NewFromUtf8(env()->isolate(), value).As<Value>();
|
|
||||||
}
|
|
||||||
case SQLITE_NULL:
|
|
||||||
return Null(env()->isolate());
|
|
||||||
case SQLITE_BLOB: {
|
|
||||||
size_t size =
|
|
||||||
static_cast<size_t>(sqlite3_column_bytes(statement_, column));
|
|
||||||
auto data = reinterpret_cast<const uint8_t*>(
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeLocal<Name> StatementSync::ColumnNameToName(const int column) {
|
MaybeLocal<Name> StatementSync::ColumnNameToName(const int column) {
|
||||||
|
@ -332,7 +332,7 @@ suite('StatementSync.prototype.setReadBigInts()', () => {
|
|||||||
bad.get();
|
bad.get();
|
||||||
}, {
|
}, {
|
||||||
code: 'ERR_OUT_OF_RANGE',
|
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`);
|
const good = db.prepare(`SELECT ${Number.MAX_SAFE_INTEGER} + 1`);
|
||||||
good.setReadBigInts(true);
|
good.setReadBigInts(true);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user