| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 457fb55 commit 1e8fa2f
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,6 +8,7 @@ | |||
| 8 | 8 | #include "node_errors.h" | |
| 9 | 9 | #include "node_mem-inl.h" | |
| 10 | 10 | #include "node_url.h" | |
| 11 | + #include "simdutf.h" | ||
| 11 | 12 | #include "sqlite3.h" | |
| 12 | 13 | #include "threadpoolwork-inl.h" | |
| 13 | 14 | #include "util-inl.h" | |
@@ -64,6 +65,20 @@ using v8::TryCatch; | |||
| 64 | 65 | using v8::Uint8Array; | |
| 65 | 66 | using v8::Value; | |
| 66 | 67 | ||
| 68 | + 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 | + | ||
| 67 | 82 | #define CHECK_ERROR_OR_THROW(isolate, db, expr, expected, ret) \ | |
| 68 | 83 | do { \ | |
| 69 | 84 | int r_ = (expr); \ | |
@@ -106,7 +121,10 @@ using v8::Value; | |||
| 106 | 121 | case SQLITE_TEXT: { \ | |
| 107 | 122 | const char* v = \ | |
| 108 | 123 | 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>(); \ | ||
| 110 | 128 | break; \ | |
| 111 | 129 | } \ | |
| 112 | 130 | case SQLITE_NULL: { \ | |
@@ -2547,6 +2565,11 @@ StatementSync::~StatementSync() { | |||
| 2547 | 2565 | void StatementSync::Finalize() { | |
| 2548 | 2566 | sqlite3_finalize(statement_); | |
| 2549 | 2567 | statement_ = nullptr; | |
| 2568 | + InvalidateColumnNameCache(); | ||
| 2569 | + } | ||
| 2570 | + | ||
| 2571 | + void StatementSync::InvalidateColumnNameCache() { | ||
| 2572 | + cached_column_names_.clear(); | ||
| 2550 | 2573 | } | |
| 2551 | 2574 | ||
| 2552 | 2575 | inline bool StatementSync::IsFinalized() { | |
@@ -2730,7 +2753,42 @@ MaybeLocal<Name> StatementSync::ColumnNameToName(const int column) { | |||
| 2730 | 2753 | return MaybeLocal<Name>(); | |
| 2731 | 2754 | } | |
| 2732 | 2755 | ||
| 2733 | - 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; | ||
| 2734 | 2792 | } | |
| 2735 | 2793 | ||
| 2736 | 2794 | MaybeLocal<Value> StatementExecutionHelper::ColumnToValue(Environment* env, | |
@@ -2752,7 +2810,9 @@ MaybeLocal<Name> StatementExecutionHelper::ColumnNameToName(Environment* env, | |||
| 2752 | 2810 | return MaybeLocal<Name>(); | |
| 2753 | 2811 | } | |
| 2754 | 2812 | ||
| 2755 | - return String::NewFromUtf8(env->isolate(), col_name).As<Name>(); | ||
| 2813 | + return String::NewFromUtf8( | ||
| 2814 | + env->isolate(), col_name, NewStringType::kInternalized) | ||
| 2815 | + .As<Name>(); | ||
| 2756 | 2816 | } | |
| 2757 | 2817 | ||
| 2758 | 2818 | void StatementSync::MemoryInfo(MemoryTracker* tracker) const {} | |
@@ -3662,12 +3722,9 @@ void StatementSyncIterator::Next(const FunctionCallbackInfo<Value>& args) { | |||
| 3662 | 3722 | if (iter->stmt_->return_arrays_) { | |
| 3663 | 3723 | row_value = Array::New(isolate, row_values.data(), row_values.size()); | |
| 3664 | 3724 | } 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; | ||
| 3671 | 3728 | ||
| 3672 | 3729 | DCHECK_EQ(row_keys.size(), row_values.size()); | |
| 3673 | 3730 | row_value = Object::New( | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -15,6 +15,7 @@ | |||
| 15 | 15 | #include <optional> | |
| 16 | 16 | #include <string_view> | |
| 17 | 17 | #include <unordered_set> | |
| 18 | + #include <vector> | ||
| 18 | 19 | ||
| 19 | 20 | namespace node { | |
| 20 | 21 | namespace sqlite { | |
@@ -279,6 +280,7 @@ class StatementSync : public BaseObject { | |||
| 279 | 280 | static void SetReturnArrays(const v8::FunctionCallbackInfo<v8::Value>& args); | |
| 280 | 281 | v8::MaybeLocal<v8::Value> ColumnToValue(const int column); | |
| 281 | 282 | v8::MaybeLocal<v8::Name> ColumnNameToName(const int column); | |
| 283 | + bool GetCachedColumnNames(v8::LocalVector<v8::Name>* keys); | ||
| 282 | 284 | void Finalize(); | |
| 283 | 285 | bool IsFinalized(); | |
| 284 | 286 | ||
@@ -296,6 +298,9 @@ class StatementSync : public BaseObject { | |||
| 296 | 298 | uint64_t reset_generation_ = 0; | |
| 297 | 299 | std::optional<std::map<std::string, std::string>> bare_named_params_; | |
| 298 | 300 | inline int ResetStatement(); | |
| 301 | + std::vector<v8::Global<v8::Name>> cached_column_names_; | ||
| 302 | + int cached_column_names_reprepare_count_ = -1; | ||
| 303 | + void InvalidateColumnNameCache(); | ||
| 299 | 304 | bool BindParams(const v8::FunctionCallbackInfo<v8::Value>& args); | |
| 300 | 305 | bool BindValue(const v8::Local<v8::Value>& value, const int index); | |
| 301 | 306 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments