Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9af115b

Browse files
committedMay 23, 2024·
Ensure values being bound aren't passed by copy
1 parent d889411 commit 9af115b

File tree

3 files changed

+36
-15
lines changed

3 files changed

+36
-15
lines changed
 

‎include/sqnice/functions.hh

+1-3
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,7 @@ namespace sqnice {
104104
void operator= (uncopied_blob v) noexcept {set_blob(v, false);}
105105

106106
template <resultable T>
107-
void operator= (T&& v) noexcept {
108-
set_helper(*this, std::forward<T>(v));
109-
}
107+
void operator= (T const& v) noexcept {set_helper(*this, v);}
110108

111109
using pointer_destructor = void(*)(void*);
112110

‎include/sqnice/query.hh

+12-12
Original file line numberDiff line numberDiff line change
@@ -204,17 +204,17 @@ namespace sqnice {
204204
}
205205

206206
template <bindable T>
207-
status bind(int idx, T&& v) {
208-
return bind_helper(*this, idx, std::forward<T>(v));
207+
status bind(int idx, T const& v) {
208+
return bind_helper(*this, idx, v);
209209
}
210210

211211
using pointer_destructor = void(*)(void*);
212212
status bind_pointer(int idx, void* pointer, const char* type, pointer_destructor);
213213

214214
/// Binds a value to a named parameter.
215215
template <typename T>
216-
status bind(char const* name, T&& v) {
217-
return bind(check_parameter_index(name), std::forward<T>(v));
216+
status bind(char const* name, T const& v) {
217+
return bind(check_parameter_index(name), v);
218218
}
219219

220220
sqlite3_stmt* stmt() const;
@@ -263,8 +263,8 @@ namespace sqnice {
263263
status bind_blob(int idx, blob value, bool copy);
264264

265265
template <typename T, typename... Args>
266-
void _bind_args(int idx, T&& arg, Args... rest) {
267-
bind(idx, std::forward<T>(arg));
266+
void _bind_args(int idx, T const& arg, Args&... rest) {
267+
bind(idx, arg);
268268
if constexpr (sizeof...(rest) > 0)
269269
_bind_args(idx + 1, rest...);
270270
}
@@ -280,7 +280,7 @@ namespace sqnice {
280280
/// Assigning a value to a `bindref` calls `bind` on the `statement`.
281281
/// @note This returns `status`, not `*this`, which is unusual for an assignment operator.
282282
template <class T>
283-
status operator= (T&& value) {return stmt_.bind(idx_, std::forward<T>(value));}
283+
status operator= (T const& value) {return stmt_.bind(idx_, value);}
284284

285285
private:
286286
friend class statement;
@@ -296,7 +296,7 @@ namespace sqnice {
296296
class statement::bindstream {
297297
public:
298298
template <class T>
299-
bindstream& operator << (T&& v) {stmt_.bind(idx_++, std::forward<T>(v)); return *this;}
299+
bindstream& operator << (T const& value) {stmt_.bind(idx_++, value); return *this;}
300300

301301
private:
302302
friend class statement;
@@ -326,12 +326,12 @@ namespace sqnice {
326326

327327
/// Binds parameters to the arguments, then executes the statement.
328328
template <typename... Args>
329-
status execute(Args... args) {_bind_args(1, args...); return execute();}
329+
status execute(Args&... args) {_bind_args(1, args...); return execute();}
330330

331331
/// Binds parameters to the arguments, then executes the statement,
332332
/// but without throwing exceptions.
333333
template <typename... Args>
334-
[[nodiscard]] status try_execute(Args... args) noexcept {
334+
[[nodiscard]] status try_execute(Args&... args) noexcept {
335335
_bind_args(1,args...);
336336
return try_execute();
337337
}
@@ -358,10 +358,10 @@ namespace sqnice {
358358

359359
/// Binds its arguments to multiple query parameters starting at index 1.
360360
template <typename... Args>
361-
query& operator() (Args... args) & {_bind_args(1, args...); return *this;}
361+
query& operator() (Args&... args) & {_bind_args(1, args...); return *this;}
362362

363363
template <typename... Args>
364-
[[nodiscard]] query operator() (Args... args) && { // (variant avoids dangling ref to
364+
[[nodiscard]] query operator() (Args&... args) && { // (variant avoids dangling ref to
365365
_bind_args(1, args...); return std::move(*this); // rvalue by returning a copy)
366366
}
367367

‎test/testquery.cc

+23
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,29 @@ TEST_CASE_METHOD(sqnice_test, "SQNice bind null", "[sqnice]") {
9595
expect_eq(nullptr, address);
9696
}
9797

98+
struct custom : sqnice::noncopyable { string str; void* self; };
99+
namespace sqnice {
100+
inline status bind_helper(statement& stmt, int idx, custom const& c) {
101+
REQUIRE(c.self == &c);
102+
return stmt.bind(idx, uncopied(c.str));
103+
}
104+
}
105+
106+
TEST_CASE_METHOD(sqnice_test, "SQNice bind nocopy", "[sqnice]") {
107+
sqnice::command cmd(db, "INSERT INTO contacts (name, phone) VALUES (?, ?)");
108+
custom c;
109+
c.str = "Longish name to ensure it gets heap allocated";
110+
c.self = &c;
111+
cmd.execute(c, "555-1234");
112+
113+
sqnice::query qry(db, "SELECT name, phone FROM contacts");
114+
auto iter = qry.begin();
115+
string name, phone;
116+
(*iter).getter() >> name >> phone;
117+
expect_eq("Longish name to ensure it gets heap allocated", name);
118+
expect_eq("555-1234", phone);
119+
}
120+
98121
TEST_CASE_METHOD(sqnice_test, "SQNice binder null", "[sqnice]") {
99122
sqnice::command cmd(db, "INSERT INTO contacts (name, phone, address) VALUES (?, ?, ?)");
100123
cmd.binder() << "Mike" << "555-1234" << nullptr;

0 commit comments

Comments
 (0)
Please sign in to comment.