Skip to content

Commit 26fa594

Browse files
cjihrigRafaelGSS
authored andcommitted
sqlite: refactor prepared statement iterator
This commit refactors the StatementSync iterator implementation in two primary ways: - The iterator internal state is no longer exposed to JavaScript. - The iterator prevents the prepared statement from being GC'ed. Fixes: #57493 PR-URL: #57569 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com> Reviewed-By: Zeyu "Alex" Yang <himself65@outlook.com>
1 parent d066d1f commit 26fa594

File tree

4 files changed

+198
-185
lines changed

4 files changed

+198
-185
lines changed

src/env_properties.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@
448448
V(shutdown_wrap_template, v8::ObjectTemplate) \
449449
V(socketaddress_constructor_template, v8::FunctionTemplate) \
450450
V(sqlite_statement_sync_constructor_template, v8::FunctionTemplate) \
451+
V(sqlite_statement_sync_iterator_constructor_template, v8::FunctionTemplate) \
451452
V(sqlite_session_constructor_template, v8::FunctionTemplate) \
452453
V(streambaseentry_ctor_template, v8::FunctionTemplate) \
453454
V(streambaseoutputstream_constructor_template, v8::ObjectTemplate) \

src/node_sqlite.cc

Lines changed: 122 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ using v8::ConstructorBehavior;
2525
using v8::Context;
2626
using v8::DontDelete;
2727
using v8::Exception;
28-
using v8::External;
2928
using v8::Function;
3029
using v8::FunctionCallback;
3130
using v8::FunctionCallbackInfo;
@@ -1620,142 +1619,12 @@ void StatementSync::All(const FunctionCallbackInfo<Value>& args) {
16201619
args.GetReturnValue().Set(Array::New(isolate, rows.data(), rows.size()));
16211620
}
16221621

1623-
void StatementSync::IterateReturnCallback(
1624-
const FunctionCallbackInfo<Value>& args) {
1625-
Environment* env = Environment::GetCurrent(args);
1626-
auto isolate = env->isolate();
1627-
auto context = isolate->GetCurrentContext();
1628-
1629-
auto self = args.This();
1630-
// iterator has fetch all result or break, prevent next func to return result
1631-
if (self->Set(context, env->isfinished_string(), Boolean::New(isolate, true))
1632-
.IsNothing()) {
1633-
// An error will have been scheduled.
1634-
return;
1635-
}
1636-
1637-
Local<Value> val;
1638-
if (!self->Get(context, env->statement_string()).ToLocal(&val)) {
1639-
// An error will have been scheduled.
1640-
return;
1641-
}
1642-
auto external_stmt = Local<External>::Cast(val);
1643-
auto stmt = static_cast<StatementSync*>(external_stmt->Value());
1644-
if (!stmt->IsFinalized()) {
1645-
sqlite3_reset(stmt->statement_);
1646-
}
1647-
1648-
LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
1649-
LocalVector<Value> values(isolate,
1650-
{Boolean::New(isolate, true), Null(isolate)});
1651-
1652-
DCHECK_EQ(keys.size(), values.size());
1653-
Local<Object> result = Object::New(
1654-
isolate, Null(isolate), keys.data(), values.data(), keys.size());
1655-
args.GetReturnValue().Set(result);
1656-
}
1657-
1658-
void StatementSync::IterateNextCallback(
1659-
const FunctionCallbackInfo<Value>& args) {
1660-
Environment* env = Environment::GetCurrent(args);
1661-
auto isolate = env->isolate();
1662-
auto context = isolate->GetCurrentContext();
1663-
1664-
auto self = args.This();
1665-
1666-
Local<Value> val;
1667-
if (!self->Get(context, env->isfinished_string()).ToLocal(&val)) {
1668-
// An error will have been scheduled.
1669-
return;
1670-
}
1671-
1672-
// skip iteration if is_finished
1673-
auto is_finished = Local<Boolean>::Cast(val);
1674-
if (is_finished->Value()) {
1675-
Local<Name> keys[] = {env->done_string(), env->value_string()};
1676-
Local<Value> values[] = {Boolean::New(isolate, true), Null(isolate)};
1677-
static_assert(arraysize(keys) == arraysize(values));
1678-
Local<Object> result = Object::New(
1679-
isolate, Null(isolate), &keys[0], &values[0], arraysize(keys));
1680-
args.GetReturnValue().Set(result);
1681-
return;
1682-
}
1683-
1684-
if (!self->Get(context, env->statement_string()).ToLocal(&val)) {
1685-
// An error will have been scheduled.
1686-
return;
1687-
}
1688-
1689-
auto external_stmt = Local<External>::Cast(val);
1690-
auto stmt = static_cast<StatementSync*>(external_stmt->Value());
1691-
1692-
if (!self->Get(context, env->num_cols_string()).ToLocal(&val)) {
1693-
// An error will have been scheduled.
1694-
return;
1695-
}
1696-
1697-
auto num_cols = Local<Integer>::Cast(val)->Value();
1698-
1699-
THROW_AND_RETURN_ON_BAD_STATE(
1700-
env, stmt->IsFinalized(), "statement has been finalized");
1701-
1702-
int r = sqlite3_step(stmt->statement_);
1703-
if (r != SQLITE_ROW) {
1704-
CHECK_ERROR_OR_THROW(
1705-
env->isolate(), stmt->db_.get(), r, SQLITE_DONE, void());
1706-
1707-
// cleanup when no more rows to fetch
1708-
sqlite3_reset(stmt->statement_);
1709-
if (self->Set(
1710-
context, env->isfinished_string(), Boolean::New(isolate, true))
1711-
.IsNothing()) {
1712-
// An error would have been scheduled
1713-
return;
1714-
}
1715-
1716-
LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
1717-
LocalVector<Value> values(isolate,
1718-
{Boolean::New(isolate, true), Null(isolate)});
1719-
1720-
DCHECK_EQ(keys.size(), values.size());
1721-
Local<Object> result = Object::New(
1722-
isolate, Null(isolate), keys.data(), values.data(), keys.size());
1723-
args.GetReturnValue().Set(result);
1724-
return;
1725-
}
1726-
1727-
LocalVector<Name> row_keys(isolate);
1728-
row_keys.reserve(num_cols);
1729-
LocalVector<Value> row_values(isolate);
1730-
row_values.reserve(num_cols);
1731-
for (int i = 0; i < num_cols; ++i) {
1732-
Local<Name> key;
1733-
if (!stmt->ColumnNameToName(i).ToLocal(&key)) return;
1734-
Local<Value> val;
1735-
if (!stmt->ColumnToValue(i).ToLocal(&val)) return;
1736-
row_keys.emplace_back(key);
1737-
row_values.emplace_back(val);
1738-
}
1739-
1740-
Local<Object> row = Object::New(
1741-
isolate, Null(isolate), row_keys.data(), row_values.data(), num_cols);
1742-
1743-
LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
1744-
LocalVector<Value> values(isolate, {Boolean::New(isolate, false), row});
1745-
1746-
DCHECK_EQ(keys.size(), values.size());
1747-
Local<Object> result = Object::New(
1748-
isolate, Null(isolate), keys.data(), values.data(), keys.size());
1749-
args.GetReturnValue().Set(result);
1750-
}
1751-
17521622
void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
17531623
StatementSync* stmt;
17541624
ASSIGN_OR_RETURN_UNWRAP(&stmt, args.This());
17551625
Environment* env = Environment::GetCurrent(args);
17561626
THROW_AND_RETURN_ON_BAD_STATE(
17571627
env, stmt->IsFinalized(), "statement has been finalized");
1758-
auto isolate = env->isolate();
17591628
auto context = env->context();
17601629
int r = sqlite3_reset(stmt->statement_);
17611630
CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void());
@@ -1764,67 +1633,28 @@ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
17641633
return;
17651634
}
17661635

1767-
Local<Function> next_func;
1768-
Local<Function> return_func;
1769-
if (!Function::New(context, StatementSync::IterateNextCallback)
1770-
.ToLocal(&next_func) ||
1771-
!Function::New(context, StatementSync::IterateReturnCallback)
1772-
.ToLocal(&return_func)) {
1773-
// An error will have been scheduled.
1774-
return;
1775-
}
1776-
1777-
Local<Name> keys[] = {env->next_string(), env->return_string()};
1778-
Local<Value> values[] = {next_func, return_func};
1779-
static_assert(arraysize(keys) == arraysize(values));
1780-
17811636
Local<Object> global = context->Global();
17821637
Local<Value> js_iterator;
17831638
Local<Value> js_iterator_prototype;
1784-
if (!global->Get(context, env->iterator_string()).ToLocal(&js_iterator))
1639+
if (!global->Get(context, env->iterator_string()).ToLocal(&js_iterator)) {
17851640
return;
1641+
}
17861642
if (!js_iterator.As<Object>()
17871643
->Get(context, env->prototype_string())
1788-
.ToLocal(&js_iterator_prototype))
1789-
return;
1790-
1791-
Local<Object> iterable_iterator = Object::New(
1792-
isolate, js_iterator_prototype, &keys[0], &values[0], arraysize(keys));
1793-
1794-
auto num_cols_pd = v8::PropertyDescriptor(
1795-
v8::Integer::New(isolate, sqlite3_column_count(stmt->statement_)), false);
1796-
num_cols_pd.set_enumerable(false);
1797-
num_cols_pd.set_configurable(false);
1798-
if (iterable_iterator
1799-
->DefineProperty(context, env->num_cols_string(), num_cols_pd)
1800-
.IsNothing()) {
1801-
// An error will have been scheduled.
1644+
.ToLocal(&js_iterator_prototype)) {
18021645
return;
18031646
}
18041647

1805-
auto stmt_pd =
1806-
v8::PropertyDescriptor(v8::External::New(isolate, stmt), false);
1807-
stmt_pd.set_enumerable(false);
1808-
stmt_pd.set_configurable(false);
1809-
if (iterable_iterator
1810-
->DefineProperty(context, env->statement_string(), stmt_pd)
1648+
BaseObjectPtr<StatementSyncIterator> iter =
1649+
StatementSyncIterator::Create(env, BaseObjectPtr<StatementSync>(stmt));
1650+
if (iter->object()
1651+
->GetPrototype()
1652+
.As<Object>()
1653+
->SetPrototype(context, js_iterator_prototype)
18111654
.IsNothing()) {
1812-
// An error will have been scheduled.
18131655
return;
18141656
}
1815-
1816-
auto is_finished_pd =
1817-
v8::PropertyDescriptor(v8::Boolean::New(isolate, false), true);
1818-
stmt_pd.set_enumerable(false);
1819-
stmt_pd.set_configurable(false);
1820-
if (iterable_iterator
1821-
->DefineProperty(context, env->isfinished_string(), is_finished_pd)
1822-
.IsNothing()) {
1823-
// An error will have been scheduled.
1824-
return;
1825-
}
1826-
1827-
args.GetReturnValue().Set(iterable_iterator);
1657+
args.GetReturnValue().Set(iter->object());
18281658
}
18291659

18301660
void StatementSync::Get(const FunctionCallbackInfo<Value>& args) {
@@ -2144,6 +1974,118 @@ BaseObjectPtr<StatementSync> StatementSync::Create(
21441974
return MakeBaseObject<StatementSync>(env, obj, std::move(db), stmt);
21451975
}
21461976

1977+
StatementSyncIterator::StatementSyncIterator(Environment* env,
1978+
Local<Object> object,
1979+
BaseObjectPtr<StatementSync> stmt)
1980+
: BaseObject(env, object), stmt_(std::move(stmt)) {
1981+
MakeWeak();
1982+
done_ = false;
1983+
}
1984+
1985+
StatementSyncIterator::~StatementSyncIterator() {}
1986+
void StatementSyncIterator::MemoryInfo(MemoryTracker* tracker) const {}
1987+
1988+
Local<FunctionTemplate> StatementSyncIterator::GetConstructorTemplate(
1989+
Environment* env) {
1990+
Local<FunctionTemplate> tmpl =
1991+
env->sqlite_statement_sync_iterator_constructor_template();
1992+
if (tmpl.IsEmpty()) {
1993+
Isolate* isolate = env->isolate();
1994+
tmpl = NewFunctionTemplate(isolate, IllegalConstructor);
1995+
tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "StatementSyncIterator"));
1996+
tmpl->InstanceTemplate()->SetInternalFieldCount(
1997+
StatementSync::kInternalFieldCount);
1998+
SetProtoMethod(isolate, tmpl, "next", StatementSyncIterator::Next);
1999+
SetProtoMethod(isolate, tmpl, "return", StatementSyncIterator::Return);
2000+
env->set_sqlite_statement_sync_iterator_constructor_template(tmpl);
2001+
}
2002+
return tmpl;
2003+
}
2004+
2005+
BaseObjectPtr<StatementSyncIterator> StatementSyncIterator::Create(
2006+
Environment* env, BaseObjectPtr<StatementSync> stmt) {
2007+
Local<Object> obj;
2008+
if (!GetConstructorTemplate(env)
2009+
->InstanceTemplate()
2010+
->NewInstance(env->context())
2011+
.ToLocal(&obj)) {
2012+
return BaseObjectPtr<StatementSyncIterator>();
2013+
}
2014+
2015+
return MakeBaseObject<StatementSyncIterator>(env, obj, std::move(stmt));
2016+
}
2017+
2018+
void StatementSyncIterator::Next(const FunctionCallbackInfo<Value>& args) {
2019+
StatementSyncIterator* iter;
2020+
ASSIGN_OR_RETURN_UNWRAP(&iter, args.This());
2021+
Environment* env = Environment::GetCurrent(args);
2022+
THROW_AND_RETURN_ON_BAD_STATE(
2023+
env, iter->stmt_->IsFinalized(), "statement has been finalized");
2024+
Isolate* isolate = env->isolate();
2025+
LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
2026+
2027+
if (iter->done_) {
2028+
LocalVector<Value> values(isolate,
2029+
{Boolean::New(isolate, true), Null(isolate)});
2030+
Local<Object> result = Object::New(
2031+
isolate, Null(isolate), keys.data(), values.data(), keys.size());
2032+
args.GetReturnValue().Set(result);
2033+
return;
2034+
}
2035+
2036+
int r = sqlite3_step(iter->stmt_->statement_);
2037+
if (r != SQLITE_ROW) {
2038+
CHECK_ERROR_OR_THROW(
2039+
env->isolate(), iter->stmt_->db_.get(), r, SQLITE_DONE, void());
2040+
sqlite3_reset(iter->stmt_->statement_);
2041+
LocalVector<Value> values(isolate,
2042+
{Boolean::New(isolate, true), Null(isolate)});
2043+
Local<Object> result = Object::New(
2044+
isolate, Null(isolate), keys.data(), values.data(), keys.size());
2045+
args.GetReturnValue().Set(result);
2046+
return;
2047+
}
2048+
2049+
int num_cols = sqlite3_column_count(iter->stmt_->statement_);
2050+
LocalVector<Name> row_keys(isolate);
2051+
LocalVector<Value> row_values(isolate);
2052+
row_keys.reserve(num_cols);
2053+
row_values.reserve(num_cols);
2054+
for (int i = 0; i < num_cols; ++i) {
2055+
Local<Name> key;
2056+
if (!iter->stmt_->ColumnNameToName(i).ToLocal(&key)) return;
2057+
Local<Value> val;
2058+
if (!iter->stmt_->ColumnToValue(i).ToLocal(&val)) return;
2059+
row_keys.emplace_back(key);
2060+
row_values.emplace_back(val);
2061+
}
2062+
2063+
Local<Object> row = Object::New(
2064+
isolate, Null(isolate), row_keys.data(), row_values.data(), num_cols);
2065+
LocalVector<Value> values(isolate, {Boolean::New(isolate, false), row});
2066+
Local<Object> result = Object::New(
2067+
isolate, Null(isolate), keys.data(), values.data(), keys.size());
2068+
args.GetReturnValue().Set(result);
2069+
}
2070+
2071+
void StatementSyncIterator::Return(const FunctionCallbackInfo<Value>& args) {
2072+
StatementSyncIterator* iter;
2073+
ASSIGN_OR_RETURN_UNWRAP(&iter, args.This());
2074+
Environment* env = Environment::GetCurrent(args);
2075+
THROW_AND_RETURN_ON_BAD_STATE(
2076+
env, iter->stmt_->IsFinalized(), "statement has been finalized");
2077+
Isolate* isolate = env->isolate();
2078+
2079+
sqlite3_reset(iter->stmt_->statement_);
2080+
iter->done_ = true;
2081+
LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
2082+
LocalVector<Value> values(isolate,
2083+
{Boolean::New(isolate, true), Null(isolate)});
2084+
Local<Object> result = Object::New(
2085+
isolate, Null(isolate), keys.data(), values.data(), keys.size());
2086+
args.GetReturnValue().Set(result);
2087+
}
2088+
21472089
Session::Session(Environment* env,
21482090
Local<Object> object,
21492091
BaseObjectWeakPtr<DatabaseSync> database,

src/node_sqlite.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,29 @@ class StatementSync : public BaseObject {
145145
v8::MaybeLocal<v8::Value> ColumnToValue(const int column);
146146
v8::MaybeLocal<v8::Name> ColumnNameToName(const int column);
147147

148-
static void IterateNextCallback(
149-
const v8::FunctionCallbackInfo<v8::Value>& args);
150-
static void IterateReturnCallback(
151-
const v8::FunctionCallbackInfo<v8::Value>& args);
148+
friend class StatementSyncIterator;
149+
};
150+
151+
class StatementSyncIterator : public BaseObject {
152+
public:
153+
StatementSyncIterator(Environment* env,
154+
v8::Local<v8::Object> object,
155+
BaseObjectPtr<StatementSync> stmt);
156+
void MemoryInfo(MemoryTracker* tracker) const override;
157+
static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
158+
Environment* env);
159+
static BaseObjectPtr<StatementSyncIterator> Create(
160+
Environment* env, BaseObjectPtr<StatementSync> stmt);
161+
static void Next(const v8::FunctionCallbackInfo<v8::Value>& args);
162+
static void Return(const v8::FunctionCallbackInfo<v8::Value>& args);
163+
164+
SET_MEMORY_INFO_NAME(StatementSyncIterator)
165+
SET_SELF_SIZE(StatementSyncIterator)
166+
167+
private:
168+
~StatementSyncIterator() override;
169+
BaseObjectPtr<StatementSync> stmt_;
170+
bool done_;
152171
};
153172

154173
using Sqlite3ChangesetGenFunc = int (*)(sqlite3_session*, int*, void**);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy