Skip to content

Commit 78bd3ff

Browse files
committed
Merge branch 'upstream/dev' into upstream/experimental/threadsafe_connection
1 parent 3ed7507 commit 78bd3ff

File tree

5 files changed

+88
-76
lines changed

5 files changed

+88
-76
lines changed

dev/connection_holder.h

+19-20
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@ namespace sqlite_orm {
4444
std::binary_semaphore& sync;
4545
};
4646

47-
connection_holder(std::string filename, bool openedForeverHint, std::function<void(sqlite3*)> onAfterOpen) :
48-
_openedForeverHint{openedForeverHint}, _onAfterOpen{std::move(onAfterOpen)},
49-
filename(std::move(filename)) {}
47+
connection_holder(std::string filename, bool openedForeverHint, std::function<void(sqlite3*)> didOpenDb) :
48+
_openedForeverHint{openedForeverHint}, _didOpenDb{std::move(didOpenDb)}, filename(std::move(filename)) {
49+
}
5050

5151
connection_holder(const connection_holder&) = delete;
5252

53-
connection_holder(const connection_holder& other, std::function<void(sqlite3*)> onAfterOpen) :
54-
filename{other.filename}, _openedForeverHint{other._openedForeverHint},
55-
_onAfterOpen{std::move(onAfterOpen)} {}
53+
connection_holder(const connection_holder& other, std::function<void(sqlite3*)> didOpenDb) :
54+
_openedForeverHint{other._openedForeverHint}, _didOpenDb{std::move(didOpenDb)},
55+
filename{other.filename} {}
5656

5757
void retain() {
5858
const maybe_lock maybeLock{_sync, !_openedForeverHint};
@@ -74,8 +74,8 @@ namespace sqlite_orm {
7474
throw_translated_sqlite_error(this->db);
7575
}
7676

77-
if (_onAfterOpen) {
78-
_onAfterOpen(this->db);
77+
if (_didOpenDb) {
78+
_didOpenDb(this->db);
7979
}
8080
}
8181

@@ -95,7 +95,7 @@ namespace sqlite_orm {
9595

9696
// last one closes the connection.
9797

98-
if (int rc = sqlite3_close(this->db); rc != SQLITE_OK) [[unlikely]] {
98+
if (int rc = sqlite3_close_v2(this->db); rc != SQLITE_OK) [[unlikely]] {
9999
throw_translated_sqlite_error(this->db);
100100
} else {
101101
this->db = nullptr;
@@ -123,8 +123,7 @@ namespace sqlite_orm {
123123
std::binary_semaphore _sync{1};
124124

125125
private:
126-
alignas(
127-
polyfill::hardware_destructive_interference_size) const std::function<void(sqlite3* db)> _onAfterOpen;
126+
alignas(polyfill::hardware_destructive_interference_size) const std::function<void(sqlite3* db)> _didOpenDb;
128127

129128
public:
130129
const std::string filename;
@@ -133,13 +132,13 @@ namespace sqlite_orm {
133132
struct connection_holder {
134133
connection_holder(std::string filename,
135134
bool /*openedForeverHint*/,
136-
std::function<void(sqlite3*)> onAfterOpen) :
137-
_onAfterOpen{std::move(onAfterOpen)}, filename(std::move(filename)) {}
135+
std::function<void(sqlite3*)> didOpenDb) :
136+
_didOpenDb{std::move(didOpenDb)}, filename(std::move(filename)) {}
138137

139138
connection_holder(const connection_holder&) = delete;
140139

141-
connection_holder(const connection_holder& other, std::function<void(sqlite3*)> onAfterOpen) :
142-
_onAfterOpen{std::move(onAfterOpen)}, filename{other.filename} {}
140+
connection_holder(const connection_holder& other, std::function<void(sqlite3*)> didOpenDb) :
141+
_didOpenDb{std::move(didOpenDb)}, filename{other.filename} {}
143142

144143
void retain() {
145144
// first one opens the connection.
@@ -153,18 +152,18 @@ namespace sqlite_orm {
153152
if (rc != SQLITE_OK) SQLITE_ORM_CPP_UNLIKELY /*possible, but unexpected*/ {
154153
throw_translated_sqlite_error(this->db);
155154
}
156-
}
157155

158-
if (_onAfterOpen) {
159-
_onAfterOpen(this->db);
156+
if (_didOpenDb) {
157+
_didOpenDb(this->db);
158+
}
160159
}
161160
}
162161

163162
void release() {
164163
// last one closes the connection.
165164
// we assume that this might happen by any thread, therefore the counter must serve as a synchronization point.
166165
if (_retainCount.fetch_sub(1, std::memory_order_acq_rel) == 1) {
167-
int rc = sqlite3_close(this->db);
166+
int rc = sqlite3_close_v2(this->db);
168167
if (rc != SQLITE_OK) SQLITE_ORM_CPP_UNLIKELY {
169168
throw_translated_sqlite_error(this->db);
170169
} else {
@@ -198,7 +197,7 @@ namespace sqlite_orm {
198197
#ifdef SQLITE_ORM_ALIGNED_NEW_SUPPORTED
199198
alignas(polyfill::hardware_destructive_interference_size)
200199
#endif
201-
const std::function<void(sqlite3* db)> _onAfterOpen;
200+
const std::function<void(sqlite3* db)> _didOpenDb;
202201

203202
public:
204203
const std::string filename;

dev/storage.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -1739,7 +1739,11 @@ namespace sqlite_orm {
17391739
SQLITE_ORM_EXPORT namespace sqlite_orm {
17401740
#ifdef SQLITE_ORM_CTAD_SUPPORTED
17411741
/*
1742-
* Factory function for a storage, from a database file and a bunch of database object definitions.
1742+
* Factory function for a storage instance, from a database file, a set of database object definitions
1743+
* and option storage options like connection control options and an 'on open' callback.
1744+
*
1745+
* E.g.
1746+
* auto storage = make_storage("", connection_control{.open_forever = true}, on_open([](sqlite3* db) {}));
17431747
*/
17441748
template<class... Spec>
17451749
auto make_storage(std::string filename, Spec... specifications) {

dev/storage_impl.h

+8-11
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,15 @@ namespace sqlite_orm {
7070
constexpr decltype(auto) materialize_column_pointer(const DBOs&,
7171
const column_pointer<Moniker, alias_holder<ColAlias>>&) {
7272
using table_type = storage_pick_table_t<Moniker, DBOs>;
73-
using cte_mapper_type = cte_mapper_type_t<table_type>;
73+
using cte_colrefs_tuple = typename cte_mapper_type_t<table_type>::final_colrefs_tuple;
74+
using cte_fields_type = typename cte_mapper_type_t<table_type>::fields_type;
7475

7576
// lookup ColAlias in the final column references
76-
using colalias_index =
77-
find_tuple_type<typename cte_mapper_type::final_colrefs_tuple, alias_holder<ColAlias>>;
78-
static_assert(colalias_index::value < std::tuple_size_v<typename cte_mapper_type::final_colrefs_tuple>,
77+
using colalias_index = find_tuple_type<cte_colrefs_tuple, alias_holder<ColAlias>>;
78+
static_assert(colalias_index::value < std::tuple_size_v<cte_colrefs_tuple>,
7979
"No such column mapped into the CTE.");
8080

81-
return &aliased_field<
82-
ColAlias,
83-
std::tuple_element_t<colalias_index::value, typename cte_mapper_type::fields_type>>::field;
81+
return &aliased_field<ColAlias, std::tuple_element_t<colalias_index::value, cte_fields_type>>::field;
8482
}
8583
#endif
8684

@@ -104,14 +102,13 @@ namespace sqlite_orm {
104102
constexpr decltype(auto) find_column_name(const DBOs& dboObjects,
105103
const column_pointer<Moniker, alias_holder<ColAlias>>&) {
106104
using table_type = storage_pick_table_t<Moniker, DBOs>;
107-
using cte_mapper_type = cte_mapper_type_t<table_type>;
105+
using cte_colrefs_tuple = typename cte_mapper_type_t<table_type>::final_colrefs_tuple;
108106
using column_index_sequence = filter_tuple_sequence_t<elements_type_t<table_type>, is_column>;
109107

110108
// note: even though the columns contain the [`aliased_field<>::*`] we perform the lookup using the column references.
111109
// lookup ColAlias in the final column references
112-
using colalias_index =
113-
find_tuple_type<typename cte_mapper_type::final_colrefs_tuple, alias_holder<ColAlias>>;
114-
static_assert(colalias_index::value < std::tuple_size_v<typename cte_mapper_type::final_colrefs_tuple>,
110+
using colalias_index = find_tuple_type<cte_colrefs_tuple, alias_holder<ColAlias>>;
111+
static_assert(colalias_index::value < std::tuple_size_v<cte_colrefs_tuple>,
115112
"No such column mapped into the CTE.");
116113

117114
// note: we could "materialize" the alias to an `aliased_field<>::*` and use the regular `table_t<>::find_column_name()` mechanism;

include/sqlite_orm/sqlite_orm.h

+32-32
Original file line numberDiff line numberDiff line change
@@ -12704,17 +12704,15 @@ namespace sqlite_orm {
1270412704
constexpr decltype(auto) materialize_column_pointer(const DBOs&,
1270512705
const column_pointer<Moniker, alias_holder<ColAlias>>&) {
1270612706
using table_type = storage_pick_table_t<Moniker, DBOs>;
12707-
using cte_mapper_type = cte_mapper_type_t<table_type>;
12707+
using cte_colrefs_tuple = typename cte_mapper_type_t<table_type>::final_colrefs_tuple;
12708+
using cte_fields_type = typename cte_mapper_type_t<table_type>::fields_type;
1270812709

1270912710
// lookup ColAlias in the final column references
12710-
using colalias_index =
12711-
find_tuple_type<typename cte_mapper_type::final_colrefs_tuple, alias_holder<ColAlias>>;
12712-
static_assert(colalias_index::value < std::tuple_size_v<typename cte_mapper_type::final_colrefs_tuple>,
12711+
using colalias_index = find_tuple_type<cte_colrefs_tuple, alias_holder<ColAlias>>;
12712+
static_assert(colalias_index::value < std::tuple_size_v<cte_colrefs_tuple>,
1271312713
"No such column mapped into the CTE.");
1271412714

12715-
return &aliased_field<
12716-
ColAlias,
12717-
std::tuple_element_t<colalias_index::value, typename cte_mapper_type::fields_type>>::field;
12715+
return &aliased_field<ColAlias, std::tuple_element_t<colalias_index::value, cte_fields_type>>::field;
1271812716
}
1271912717
#endif
1272012718

@@ -12738,14 +12736,13 @@ namespace sqlite_orm {
1273812736
constexpr decltype(auto) find_column_name(const DBOs& dboObjects,
1273912737
const column_pointer<Moniker, alias_holder<ColAlias>>&) {
1274012738
using table_type = storage_pick_table_t<Moniker, DBOs>;
12741-
using cte_mapper_type = cte_mapper_type_t<table_type>;
12739+
using cte_colrefs_tuple = typename cte_mapper_type_t<table_type>::final_colrefs_tuple;
1274212740
using column_index_sequence = filter_tuple_sequence_t<elements_type_t<table_type>, is_column>;
1274312741

1274412742
// note: even though the columns contain the [`aliased_field<>::*`] we perform the lookup using the column references.
1274512743
// lookup ColAlias in the final column references
12746-
using colalias_index =
12747-
find_tuple_type<typename cte_mapper_type::final_colrefs_tuple, alias_holder<ColAlias>>;
12748-
static_assert(colalias_index::value < std::tuple_size_v<typename cte_mapper_type::final_colrefs_tuple>,
12744+
using colalias_index = find_tuple_type<cte_colrefs_tuple, alias_holder<ColAlias>>;
12745+
static_assert(colalias_index::value < std::tuple_size_v<cte_colrefs_tuple>,
1274912746
"No such column mapped into the CTE.");
1275012747

1275112748
// note: we could "materialize" the alias to an `aliased_field<>::*` and use the regular `table_t<>::find_column_name()` mechanism;
@@ -13981,15 +13978,15 @@ namespace sqlite_orm {
1398113978
std::binary_semaphore& sync;
1398213979
};
1398313980

13984-
connection_holder(std::string filename, bool openedForeverHint, std::function<void(sqlite3*)> onAfterOpen) :
13985-
_openedForeverHint{openedForeverHint}, _onAfterOpen{std::move(onAfterOpen)},
13986-
filename(std::move(filename)) {}
13981+
connection_holder(std::string filename, bool openedForeverHint, std::function<void(sqlite3*)> didOpenDb) :
13982+
_openedForeverHint{openedForeverHint}, _didOpenDb{std::move(didOpenDb)}, filename(std::move(filename)) {
13983+
}
1398713984

1398813985
connection_holder(const connection_holder&) = delete;
1398913986

13990-
connection_holder(const connection_holder& other, std::function<void(sqlite3*)> onAfterOpen) :
13991-
filename{other.filename}, _openedForeverHint{other._openedForeverHint},
13992-
_onAfterOpen{std::move(onAfterOpen)} {}
13987+
connection_holder(const connection_holder& other, std::function<void(sqlite3*)> didOpenDb) :
13988+
_openedForeverHint{other._openedForeverHint}, _didOpenDb{std::move(didOpenDb)},
13989+
filename{other.filename} {}
1399313990

1399413991
void retain() {
1399513992
const maybe_lock maybeLock{_sync, !_openedForeverHint};
@@ -14011,8 +14008,8 @@ namespace sqlite_orm {
1401114008
throw_translated_sqlite_error(this->db);
1401214009
}
1401314010

14014-
if (_onAfterOpen) {
14015-
_onAfterOpen(this->db);
14011+
if (_didOpenDb) {
14012+
_didOpenDb(this->db);
1401614013
}
1401714014
}
1401814015

@@ -14032,7 +14029,7 @@ namespace sqlite_orm {
1403214029

1403314030
// last one closes the connection.
1403414031

14035-
if (int rc = sqlite3_close(this->db); rc != SQLITE_OK) [[unlikely]] {
14032+
if (int rc = sqlite3_close_v2(this->db); rc != SQLITE_OK) [[unlikely]] {
1403614033
throw_translated_sqlite_error(this->db);
1403714034
} else {
1403814035
this->db = nullptr;
@@ -14060,8 +14057,7 @@ namespace sqlite_orm {
1406014057
std::binary_semaphore _sync{1};
1406114058

1406214059
private:
14063-
alignas(
14064-
polyfill::hardware_destructive_interference_size) const std::function<void(sqlite3* db)> _onAfterOpen;
14060+
alignas(polyfill::hardware_destructive_interference_size) const std::function<void(sqlite3* db)> _didOpenDb;
1406514061

1406614062
public:
1406714063
const std::string filename;
@@ -14070,13 +14066,13 @@ namespace sqlite_orm {
1407014066
struct connection_holder {
1407114067
connection_holder(std::string filename,
1407214068
bool /*openedForeverHint*/,
14073-
std::function<void(sqlite3*)> onAfterOpen) :
14074-
_onAfterOpen{std::move(onAfterOpen)}, filename(std::move(filename)) {}
14069+
std::function<void(sqlite3*)> didOpenDb) :
14070+
_didOpenDb{std::move(didOpenDb)}, filename(std::move(filename)) {}
1407514071

1407614072
connection_holder(const connection_holder&) = delete;
1407714073

14078-
connection_holder(const connection_holder& other, std::function<void(sqlite3*)> onAfterOpen) :
14079-
_onAfterOpen{std::move(onAfterOpen)}, filename{other.filename} {}
14074+
connection_holder(const connection_holder& other, std::function<void(sqlite3*)> didOpenDb) :
14075+
_didOpenDb{std::move(didOpenDb)}, filename{other.filename} {}
1408014076

1408114077
void retain() {
1408214078
// first one opens the connection.
@@ -14090,18 +14086,18 @@ namespace sqlite_orm {
1409014086
if (rc != SQLITE_OK) SQLITE_ORM_CPP_UNLIKELY /*possible, but unexpected*/ {
1409114087
throw_translated_sqlite_error(this->db);
1409214088
}
14093-
}
1409414089

14095-
if (_onAfterOpen) {
14096-
_onAfterOpen(this->db);
14090+
if (_didOpenDb) {
14091+
_didOpenDb(this->db);
14092+
}
1409714093
}
1409814094
}
1409914095

1410014096
void release() {
1410114097
// last one closes the connection.
1410214098
// we assume that this might happen by any thread, therefore the counter must serve as a synchronization point.
1410314099
if (_retainCount.fetch_sub(1, std::memory_order_acq_rel) == 1) {
14104-
int rc = sqlite3_close(this->db);
14100+
int rc = sqlite3_close_v2(this->db);
1410514101
if (rc != SQLITE_OK) SQLITE_ORM_CPP_UNLIKELY {
1410614102
throw_translated_sqlite_error(this->db);
1410714103
} else {
@@ -14135,7 +14131,7 @@ namespace sqlite_orm {
1413514131
#ifdef SQLITE_ORM_ALIGNED_NEW_SUPPORTED
1413614132
alignas(polyfill::hardware_destructive_interference_size)
1413714133
#endif
14138-
const std::function<void(sqlite3* db)> _onAfterOpen;
14134+
const std::function<void(sqlite3* db)> _didOpenDb;
1413914135

1414014136
public:
1414114137
const std::string filename;
@@ -24362,7 +24358,11 @@ namespace sqlite_orm {
2436224358
SQLITE_ORM_EXPORT namespace sqlite_orm {
2436324359
#ifdef SQLITE_ORM_CTAD_SUPPORTED
2436424360
/*
24365-
* Factory function for a storage, from a database file and a bunch of database object definitions.
24361+
* Factory function for a storage instance, from a database file, a set of database object definitions
24362+
* and option storage options like connection control options and an 'on open' callback.
24363+
*
24364+
* E.g.
24365+
* auto storage = make_storage("", connection_control{.open_forever = true}, on_open([](sqlite3* db) {}));
2436624366
*/
2436724367
template<class... Spec>
2436824368
auto make_storage(std::string filename, Spec... specifications) {

tests/storage_tests.cpp

+24-12
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,51 @@ TEST_CASE("connection control") {
99
const auto openForever = GENERATE(false, true);
1010
SECTION("") {
1111
bool onOpenCalled = false;
12+
int nOnOpenCalled = 0;
1213
SECTION("empty") {
13-
auto storage = make_storage("", connection_control{openForever}, on_open([&onOpenCalled](sqlite3* db) {
14-
onOpenCalled = db || false;
15-
}));
14+
auto storage =
15+
make_storage("", connection_control{openForever}, on_open([&onOpenCalled, &nOnOpenCalled](sqlite3* db) {
16+
onOpenCalled = db || false;
17+
++nOnOpenCalled;
18+
}));
1619
REQUIRE(storage.is_opened());
1720
REQUIRE(onOpenCalled);
21+
REQUIRE(nOnOpenCalled == 1);
1822
}
1923
#if __cpp_designated_initializers >= 201707L
2024
SECTION("empty C++20") {
21-
auto storage =
22-
make_storage("", connection_control{.open_forever = openForever}, on_open([&onOpenCalled](sqlite3* db) {
23-
onOpenCalled = db || false;
24-
}));
25+
auto storage = make_storage("",
26+
connection_control{.open_forever = openForever},
27+
on_open([&onOpenCalled, &nOnOpenCalled](sqlite3* db) {
28+
onOpenCalled = db || false;
29+
++nOnOpenCalled;
30+
}));
2531
REQUIRE(storage.is_opened());
2632
REQUIRE(onOpenCalled);
33+
REQUIRE(nOnOpenCalled == 1);
2734
}
2835
#endif
2936
SECTION("memory") {
30-
auto storage =
31-
make_storage(":memory:", connection_control{openForever}, on_open([&onOpenCalled](sqlite3* db) {
32-
onOpenCalled = db || false;
33-
}));
37+
auto storage = make_storage(":memory:",
38+
connection_control{openForever},
39+
on_open([&onOpenCalled, &nOnOpenCalled](sqlite3* db) {
40+
onOpenCalled = db || false;
41+
++nOnOpenCalled;
42+
}));
3443
REQUIRE(storage.is_opened());
3544
REQUIRE(onOpenCalled);
45+
REQUIRE(nOnOpenCalled == 1);
3646
}
3747
SECTION("file name") {
3848
auto storage = make_storage("myDatabase.sqlite",
3949
connection_control{openForever},
40-
on_open([&onOpenCalled](sqlite3* db) {
50+
on_open([&onOpenCalled, &nOnOpenCalled](sqlite3* db) {
4151
onOpenCalled = db || false;
52+
++nOnOpenCalled;
4253
}));
4354
REQUIRE(storage.is_opened() == openForever);
4455
REQUIRE(onOpenCalled == openForever);
56+
REQUIRE(nOnOpenCalled == int(openForever));
4557
}
4658
}
4759
}

0 commit comments

Comments
 (0)