◐ Shell
clean mode source ↗

sqlite: use OneByte for ASCII text and internalize col names · nodejs/node@2f37f91

@@ -8,6 +8,7 @@

88

#include "node_errors.h"

99

#include "node_mem-inl.h"

1010

#include "node_url.h"

11+

#include "simdutf.h"

1112

#include "sqlite3.h"

1213

#include "threadpoolwork-inl.h"

1314

#include "util-inl.h"

@@ -64,6 +65,20 @@ using v8::TryCatch;

6465

using v8::Uint8Array;

6566

using v8::Value;

666768+

inline MaybeLocal<String> Utf8StringMaybeOneByte(Isolate* isolate,

69+

std::string_view input) {

70+

const int len = static_cast<int>(input.size());

71+

if (simdutf::validate_ascii(input.data(), input.size())) {

72+

return String::NewFromOneByte(

73+

isolate,

74+

reinterpret_cast<const uint8_t*>(input.data()),

75+

NewStringType::kNormal,

76+

len);

77+

}

78+

return String::NewFromUtf8(

79+

isolate, input.data(), NewStringType::kNormal, len);

80+

}

81+6782

#define CHECK_ERROR_OR_THROW(isolate, db, expr, expected, ret) \

6883

do { \

6984

int r_ = (expr); \

@@ -106,7 +121,10 @@ using v8::Value;

106121

case SQLITE_TEXT: { \

107122

const char* v = \

108123

reinterpret_cast<const char*>(sqlite3_##from##_text(__VA_ARGS__)); \

109-

(result) = String::NewFromUtf8((isolate), v).As<Value>(); \

124+

const int v_len = sqlite3_##from##_bytes(__VA_ARGS__); \

125+

(result) = \

126+

Utf8StringMaybeOneByte((isolate), std::string_view(v, v_len)) \

127+

.As<Value>(); \

110128

break; \

111129

} \

112130

case SQLITE_NULL: { \

@@ -2547,6 +2565,11 @@ StatementSync::~StatementSync() {

25472565

void StatementSync::Finalize() {

25482566

sqlite3_finalize(statement_);

25492567

statement_ = nullptr;

2568+

InvalidateColumnNameCache();

2569+

}

2570+2571+

void StatementSync::InvalidateColumnNameCache() {

2572+

cached_column_names_.clear();

25502573

}

2551257425522575

inline bool StatementSync::IsFinalized() {

@@ -2730,7 +2753,42 @@ MaybeLocal<Name> StatementSync::ColumnNameToName(const int column) {

27302753

return MaybeLocal<Name>();

27312754

}

273227552733-

return String::NewFromUtf8(env()->isolate(), col_name).As<Name>();

2756+

return String::NewFromUtf8(

2757+

env()->isolate(), col_name, NewStringType::kInternalized)

2758+

.As<Name>();

2759+

}

2760+2761+

// Populates `keys` with cached column names, rebuilding the cache if the

2762+

// statement was re-prepared.

2763+

bool StatementSync::GetCachedColumnNames(LocalVector<Name>* keys) {

2764+

Isolate* isolate = env()->isolate();

2765+2766+

const int reprepare_count =

2767+

sqlite3_stmt_status(statement_, SQLITE_STMTSTATUS_REPREPARE, false);

2768+

if (reprepare_count != cached_column_names_reprepare_count_) {

2769+

cached_column_names_.clear();

2770+

const int num_cols = sqlite3_column_count(statement_);

2771+

if (num_cols == 0) {

2772+

cached_column_names_reprepare_count_ = reprepare_count;

2773+

return true;

2774+

}

2775+

cached_column_names_.reserve(num_cols);

2776+

for (int i = 0; i < num_cols; ++i) {

2777+

Local<Name> key;

2778+

if (!ColumnNameToName(i).ToLocal(&key)) {

2779+

InvalidateColumnNameCache();

2780+

return false;

2781+

}

2782+

cached_column_names_.emplace_back(Global<Name>(isolate, key));

2783+

}

2784+

cached_column_names_reprepare_count_ = reprepare_count;

2785+

}

2786+2787+

keys->reserve(cached_column_names_.size());

2788+

for (const auto& name : cached_column_names_) {

2789+

keys->emplace_back(name.Get(isolate));

2790+

}

2791+

return true;

27342792

}

2735279327362794

MaybeLocal<Value> StatementExecutionHelper::ColumnToValue(Environment* env,

@@ -2752,7 +2810,9 @@ MaybeLocal<Name> StatementExecutionHelper::ColumnNameToName(Environment* env,

27522810

return MaybeLocal<Name>();

27532811

}

275428122755-

return String::NewFromUtf8(env->isolate(), col_name).As<Name>();

2813+

return String::NewFromUtf8(

2814+

env->isolate(), col_name, NewStringType::kInternalized)

2815+

.As<Name>();

27562816

}

2757281727582818

void StatementSync::MemoryInfo(MemoryTracker* tracker) const {}

@@ -3662,12 +3722,9 @@ void StatementSyncIterator::Next(const FunctionCallbackInfo<Value>& args) {

36623722

if (iter->stmt_->return_arrays_) {

36633723

row_value = Array::New(isolate, row_values.data(), row_values.size());

36643724

} else {

3665-

row_keys.reserve(num_cols);

3666-

for (int i = 0; i < num_cols; ++i) {

3667-

Local<Name> key;

3668-

if (!iter->stmt_->ColumnNameToName(i).ToLocal(&key)) return;

3669-

row_keys.emplace_back(key);

3670-

}

3725+

// Use cached internalized column names to avoid repeated V8 string

3726+

// creation and enable hidden class sharing across row objects.

3727+

if (!iter->stmt_->GetCachedColumnNames(&row_keys)) return;

3671372836723729

DCHECK_EQ(row_keys.size(), row_values.size());

36733730

row_value = Object::New(