Skip to content

Commit 60bbaab

Browse files
committed
bugfix dangling reference πŸ˜΅β€πŸ’«πŸ˜²πŸ™ƒ
The QueryGrammar instance was dangling reference after a connection was removed and created again.
1 parent 065333b commit 60bbaab

File tree

12 files changed

+106
-71
lines changed

12 files changed

+106
-71
lines changed

β€Žinclude/orm/query/grammars/grammar.hppβ€Ž

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,19 @@ namespace Orm::Query::Grammars
9696
struct SelectComponentValue
9797
{
9898
/*! The component's compile method. */
99-
std::function<QString(const QueryBuilder &)> compileMethod;
99+
std::function<QString(const Grammar &, const QueryBuilder &)> compileMethod;
100100
/*! Determine whether the component is set and is not empty. */
101101
std::function<bool(const QueryBuilder &)> isset;
102102
};
103+
/*! Alias type for the whereXx() methods. */
104+
using WhereMemFn = std::function<QString(const Grammar &grammar,
105+
const WhereConditionItem &)>;
103106

104107
/*! Map the ComponentType to a Grammar::compileXx() methods. */
105108
virtual const QMap<SelectComponentType, SelectComponentValue> &
106109
getCompileMap() const = 0;
107110
/*! Map the WhereType to a Grammar::whereXx() methods. */
108-
virtual const std::function<QString(const WhereConditionItem &)> &
109-
getWhereMethod(WhereType whereType) const = 0;
111+
virtual const WhereMemFn &getWhereMethod(WhereType whereType) const = 0;
110112

111113
/*! Determine whether the 'aggregate' component should be compiled. */
112114
static bool shouldCompileAggregate(const std::optional<AggregateItem> &aggregate);

β€Žinclude/orm/query/grammars/mysqlgrammar.hppβ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ namespace Orm::Query::Grammars
5353
const QMap<SelectComponentType, SelectComponentValue> &
5454
getCompileMap() const override;
5555
/*! Map the WhereType to a Grammar::whereXx() methods. */
56-
const std::function<QString(const WhereConditionItem &)> &
57-
getWhereMethod(WhereType whereType) const override;
56+
const WhereMemFn &getWhereMethod(WhereType whereType) const override;
5857

5958
/*! Compile an update statement without joins into SQL. */
6059
QString

β€Žinclude/orm/query/grammars/postgresgrammar.hppβ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ namespace Orm::Query::Grammars
6262
const QMap<SelectComponentType, SelectComponentValue> &
6363
getCompileMap() const override;
6464
/*! Map the WhereType to a Grammar::whereXx() methods. */
65-
const std::function<QString(const WhereConditionItem &)> &
66-
getWhereMethod(WhereType whereType) const override;
65+
const WhereMemFn &getWhereMethod(WhereType whereType) const override;
6766

6867
/*! Compile the "select *" portion of the query. */
6968
QString compileColumns(const QueryBuilder &query) const override;

β€Žinclude/orm/query/grammars/sqlitegrammar.hppβ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ namespace Orm::Query::Grammars
5555
const QMap<SelectComponentType, SelectComponentValue> &
5656
getCompileMap() const override;
5757
/*! Map the WhereType to a Grammar::whereXx() methods. */
58-
const std::function<QString(const WhereConditionItem &)> &
59-
getWhereMethod(WhereType whereType) const override;
58+
const WhereMemFn &getWhereMethod(WhereType whereType) const override;
6059

6160
/*! Compile a "where date" clause. */
6261
QString whereDate(const WhereConditionItem &where) const;

β€Žsrc/orm/query/grammars/grammar.cppβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ QStringList Grammar::compileComponents(const QueryBuilder &query) const
194194

195195
for (const auto &component : compileMap)
196196
if (component.isset && component.isset(query))
197-
sql << std::invoke(component.compileMethod, query);
197+
sql << std::invoke(component.compileMethod, *this, query);
198198

199199
return sql;
200200
}
@@ -268,7 +268,7 @@ QStringList Grammar::compileWheresToVector(const QueryBuilder &query) const
268268

269269
for (const auto &where : wheres)
270270
compiledWheres << SPACE_IN.arg(where.condition,
271-
std::invoke(getWhereMethod(where.type), where));
271+
std::invoke(getWhereMethod(where.type), *this, where));
272272

273273
return compiledWheres;
274274
}

β€Žsrc/orm/query/grammars/mysqlgrammar.cppβ€Ž

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "orm/query/grammars/mysqlgrammar.hpp"
22

3-
#include "orm/macros/threadlocal.hpp"
43
#include "orm/mysqlconnection.hpp"
54
#include "orm/query/querybuilder.hpp"
65

@@ -105,18 +104,20 @@ MySqlGrammar::getCompileMap() const
105104
'this' reference and the compileMethod rvalue reference in the following lambda
106105
and simply save std::function<> in the SelectComponentValue's compileMethod data
107106
member. */
108-
const auto bind = [this](auto &&compileMethod)
107+
const auto bind = [](auto &&compileMethod)
109108
{
110-
return [this,
111-
compileMethod = std::forward<decltype (compileMethod)>(compileMethod)]
112-
(const auto &query)
109+
return [compileMethod = std::forward<decltype (compileMethod)>(compileMethod)]
110+
(const Grammar &grammar, const QueryBuilder &query)
113111
{
114-
return std::invoke(compileMethod, this, query);
112+
/* We can be at 100% sure that this is the MySqlGrammar instance because
113+
this method is virtual; used the reinterpret_cast<> to avoid useless
114+
and slower dynamic_cast<>. */
115+
return std::invoke(compileMethod,
116+
reinterpret_cast<const MySqlGrammar &>(grammar), query);
115117
};
116118
};
117119

118120
// Pointers to a where member methods by whereType, yes yes c++ πŸ˜‚
119-
T_THREAD_LOCAL
120121
static const QMap<SelectComponentType, SelectComponentValue> cached {
121122
{SelectComponentType::AGGREGATE, {bind(&MySqlGrammar::compileAggregate),
122123
[](const auto &query)
@@ -148,28 +149,30 @@ MySqlGrammar::getCompileMap() const
148149
return cached;
149150
}
150151

151-
const std::function<QString(const WhereConditionItem &)> &
152+
const Grammar::WhereMemFn &
152153
MySqlGrammar::getWhereMethod(const WhereType whereType) const
153154
{
154155
/* Needed, because some compileXx() methods are overloaded, this way I will capture
155156
'this' reference and the compileMethod rvalue reference in the following lambda
156157
and simply save std::function<> in the SelectComponentValue's compileMethod data
157158
member. */
158-
const auto bind = [this](auto &&compileMethod)
159+
const auto bind = [](auto &&compileMethod)
159160
{
160-
return [this,
161-
compileMethod = std::forward<decltype (compileMethod)>(compileMethod)]
162-
(const auto &query)
161+
return [compileMethod = std::forward<decltype (compileMethod)>(compileMethod)]
162+
(const Grammar &grammar, const WhereConditionItem &where)
163163
{
164-
return std::invoke(compileMethod, this, query);
164+
/* We can be at 100% sure that this is the MySqlGrammar instance because
165+
this method is virtual; used the reinterpret_cast<> to avoid useless
166+
and slower dynamic_cast<>. */
167+
return std::invoke(compileMethod,
168+
reinterpret_cast<const MySqlGrammar &>(grammar), where);
165169
};
166170
};
167171

168172
// Pointers to a where member methods by whereType, yes yes c++ πŸ˜‚
169173
// An order has to be the same as in enum struct WhereType
170174
// FUTURE QHash would has faster lookup, I should choose QHash, fix also another Grammars silverx
171-
T_THREAD_LOCAL
172-
static const QVector<std::function<QString(const WhereConditionItem &)>> cached {
175+
static const QVector<WhereMemFn> cached {
173176
bind(&MySqlGrammar::whereBasic),
174177
bind(&MySqlGrammar::whereNested),
175178
bind(&MySqlGrammar::whereColumn),
@@ -190,7 +193,6 @@ MySqlGrammar::getWhereMethod(const WhereType whereType) const
190193
bind(&MySqlGrammar::whereYear),
191194
};
192195

193-
T_THREAD_LOCAL
194196
static const auto size = cached.size();
195197

196198
// Check if whereType is in the range, just for sure 😏

β€Žsrc/orm/query/grammars/postgresgrammar.cppβ€Ž

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "orm/query/grammars/postgresgrammar.hpp"
22

3-
#include "orm/macros/threadlocal.hpp"
43
#include "orm/query/querybuilder.hpp"
54

65
TINYORM_BEGIN_COMMON_NAMESPACE
@@ -113,18 +112,20 @@ PostgresGrammar::getCompileMap() const
113112
'this' reference and the compileMethod rvalue reference in the following lambda
114113
and simply save std::function<> in the SelectComponentValue's compileMethod data
115114
member. */
116-
const auto bind = [this](auto &&compileMethod)
115+
const auto bind = [](auto &&compileMethod)
117116
{
118-
return [this,
119-
compileMethod = std::forward<decltype (compileMethod)>(compileMethod)]
120-
(const auto &query)
117+
return [compileMethod = std::forward<decltype (compileMethod)>(compileMethod)]
118+
(const Grammar &grammar, const QueryBuilder &query)
121119
{
122-
return std::invoke(compileMethod, this, query);
120+
/* We can be at 100% sure that this is the PostgresGrammar instance because
121+
this method is virtual; used the reinterpret_cast<> to avoid useless
122+
and slower dynamic_cast<>. */
123+
return std::invoke(compileMethod,
124+
reinterpret_cast<const PostgresGrammar &>(grammar), query);
123125
};
124126
};
125127

126128
// Pointers to a where member methods by whereType, yes yes c++ πŸ˜‚
127-
T_THREAD_LOCAL
128129
static const QMap<SelectComponentType, SelectComponentValue> cached {
129130
{SelectComponentType::AGGREGATE, {bind(&PostgresGrammar::compileAggregate),
130131
[](const auto &query)
@@ -155,28 +156,30 @@ PostgresGrammar::getCompileMap() const
155156
return cached;
156157
}
157158

158-
const std::function<QString(const WhereConditionItem &)> &
159+
const Grammar::WhereMemFn &
159160
PostgresGrammar::getWhereMethod(const WhereType whereType) const
160161
{
161162
/* Needed, because some compileXx() methods are overloaded, this way I will capture
162163
'this' reference and the compileMethod rvalue reference in the following lambda
163164
and simply save std::function<> in the SelectComponentValue's compileMethod data
164165
member. */
165-
const auto bind = [this](auto &&compileMethod)
166+
const auto bind = [](auto &&compileMethod)
166167
{
167-
return [this,
168-
compileMethod = std::forward<decltype (compileMethod)>(compileMethod)]
169-
(const auto &query)
168+
return [compileMethod = std::forward<decltype (compileMethod)>(compileMethod)]
169+
(const Grammar &grammar, const WhereConditionItem &query)
170170
{
171-
return std::invoke(compileMethod, this, query);
171+
/* We can be at 100% sure that this is the PostgresGrammar instance because
172+
this method is virtual; used the reinterpret_cast<> to avoid useless
173+
and slower dynamic_cast<>. */
174+
return std::invoke(compileMethod,
175+
reinterpret_cast<const PostgresGrammar &>(grammar), query);
172176
};
173177
};
174178

175179
// Pointers to a where member methods by whereType, yes yes c++ πŸ˜‚
176180
// An order has to be the same as in enum struct WhereType
177181
// FUTURE QHash would has faster lookup, I should choose QHash, fix also another Grammars silverx
178-
T_THREAD_LOCAL
179-
static const QVector<std::function<QString(const WhereConditionItem &)>> cached {
182+
static const QVector<WhereMemFn> cached {
180183
bind(&PostgresGrammar::whereBasic),
181184
bind(&PostgresGrammar::whereNested),
182185
bind(&PostgresGrammar::whereColumn),
@@ -197,7 +200,6 @@ PostgresGrammar::getWhereMethod(const WhereType whereType) const
197200
bind(&PostgresGrammar::whereYear),
198201
};
199202

200-
T_THREAD_LOCAL
201203
static const auto size = cached.size();
202204

203205
// Check if whereType is in the range, just for sure 😏

β€Žsrc/orm/query/grammars/sqlitegrammar.cppβ€Ž

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "orm/query/grammars/sqlitegrammar.hpp"
22

3-
#include "orm/macros/threadlocal.hpp"
43
#include "orm/query/querybuilder.hpp"
54

65
TINYORM_BEGIN_COMMON_NAMESPACE
@@ -92,18 +91,20 @@ SQLiteGrammar::getCompileMap() const
9291
'this' reference and the compileMethod rvalue reference in the following lambda
9392
and simply save std::function<> in the SelectComponentValue's compileMethod data
9493
member. */
95-
const auto bind = [this](auto &&compileMethod)
94+
const auto bind = [](auto &&compileMethod)
9695
{
97-
return [this,
98-
compileMethod = std::forward<decltype (compileMethod)>(compileMethod)]
99-
(const auto &query)
96+
return [compileMethod = std::forward<decltype (compileMethod)>(compileMethod)]
97+
(const Grammar &grammar, const QueryBuilder &query)
10098
{
101-
return std::invoke(compileMethod, this, query);
99+
/* We can be at 100% sure that this is the SQLiteGrammar instance because
100+
this method is virtual; used the reinterpret_cast<> to avoid useless
101+
and slower dynamic_cast<>. */
102+
return std::invoke(compileMethod,
103+
reinterpret_cast<const SQLiteGrammar &>(grammar), query);
102104
};
103105
};
104106

105107
// Pointers to a where member methods by whereType, yes yes c++ πŸ˜‚
106-
T_THREAD_LOCAL
107108
static const QMap<SelectComponentType, SelectComponentValue> cached {
108109
{SelectComponentType::AGGREGATE, {bind(&SQLiteGrammar::compileAggregate),
109110
[](const auto &query)
@@ -134,27 +135,29 @@ SQLiteGrammar::getCompileMap() const
134135
return cached;
135136
}
136137

137-
const std::function<QString(const WhereConditionItem &)> &
138+
const Grammar::WhereMemFn &
138139
SQLiteGrammar::getWhereMethod(const WhereType whereType) const
139140
{
140141
/* Needed, because some compileXx() methods are overloaded, this way I will capture
141142
'this' reference and the compileMethod rvalue reference in the following lambda
142143
and simply save std::function<> in the SelectComponentValue's compileMethod data
143144
member. */
144-
const auto bind = [this](auto &&compileMethod)
145+
const auto bind = [](auto &&compileMethod)
145146
{
146-
return [this,
147-
compileMethod = std::forward<decltype (compileMethod)>(compileMethod)]
148-
(const auto &query)
147+
return [compileMethod = std::forward<decltype (compileMethod)>(compileMethod)]
148+
(const Grammar &grammar, const WhereConditionItem &query)
149149
{
150-
return std::invoke(compileMethod, this, query);
150+
/* We can be at 100% sure that this is the SQLiteGrammar instance because
151+
this method is virtual; used the reinterpret_cast<> to avoid useless
152+
and slower dynamic_cast<>. */
153+
return std::invoke(compileMethod,
154+
reinterpret_cast<const SQLiteGrammar &>(grammar), query);
151155
};
152156
};
153157

154158
// Pointers to a where member methods by whereType, yes yes c++ πŸ˜‚
155159
// An order has to be the same as in enum struct WhereType
156-
T_THREAD_LOCAL
157-
static const QVector<std::function<QString(const WhereConditionItem &)>> cached {
160+
static const QVector<WhereMemFn> cached {
158161
bind(&SQLiteGrammar::whereBasic),
159162
bind(&SQLiteGrammar::whereNested),
160163
bind(&SQLiteGrammar::whereColumn),
@@ -175,7 +178,6 @@ SQLiteGrammar::getWhereMethod(const WhereType whereType) const
175178
bind(&SQLiteGrammar::whereYear),
176179
};
177180

178-
T_THREAD_LOCAL
179181
static const auto size = cached.size();
180182

181183
// Check if whereType is in the range, just for sure 😏

β€Žsrc/orm/schema/grammars/mysqlschemagrammar.cppβ€Ž

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#include <unordered_set>
44

55
#include "orm/databaseconnection.hpp"
6-
#include "orm/macros/threadlocal.hpp"
76
#include "orm/utils/type.hpp"
87

98
TINYORM_BEGIN_COMMON_NAMESPACE
@@ -281,7 +280,6 @@ MySqlSchemaGrammar::invokeCompileMethod(const CommandDefinition &command,
281280
I have to map by QString instead of enum struct because a command.name is used
282281
to look up, I could use enum struct but I would have to map
283282
QString(command.name) -> enum. */
284-
T_THREAD_LOCAL
285283
static const std::unordered_map<QString, CompileMemFn> cached {
286284
{Add, bind(&MySqlSchemaGrammar::compileAdd)},
287285
{Rename, bind(&MySqlSchemaGrammar::compileRename)},

β€Žsrc/orm/schema/grammars/postgresschemagrammar.cppβ€Ž

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#include <unordered_set>
44

55
#include "orm/databaseconnection.hpp"
6-
#include "orm/macros/threadlocal.hpp"
76
#include "orm/utils/type.hpp"
87

98
TINYORM_BEGIN_COMMON_NAMESPACE
@@ -338,7 +337,6 @@ PostgresSchemaGrammar::invokeCompileMethod(const CommandDefinition &command,
338337
I have to map by QString instead of enum struct because a command.name is used
339338
to look up, I could use enum struct but I would have to map
340339
QString(command.name) -> enum. */
341-
T_THREAD_LOCAL
342340
static const std::unordered_map<QString, CompileMemFn> cached {
343341
{Add, bind(&PostgresSchemaGrammar::compileAdd)},
344342
{Rename, bind(&PostgresSchemaGrammar::compileRename)},

0 commit comments

Comments
Β (0)