Skip to content

Commit 219614b

Browse files
authored
Merge pull request #120 from zauguin/autoreset
Auto reset after statement execution
2 parents 0124642 + 05ea5a8 commit 219614b

File tree

4 files changed

+37
-59
lines changed

4 files changed

+37
-59
lines changed

README.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,10 @@ ps << tmp;
117117
// But beware that it will execute on destruction if it wasn't executed!
118118
ps >> [&](int a,int b){ ... };
119119
120-
// after a successfull execution the statment needs to be reset to be execute again. This will reset the bound values too!
121-
ps.reset();
122-
120+
// after a successfull execution the statment can be executed again, but the bound values are resetted.
123121
// If you dont need the returned values you can execute it like this
124-
ps.execute(); // the statment will not be reset!
125-
126-
// there is a convinience operator to execute and reset in one go
122+
ps.execute();
123+
// or like this
127124
ps++;
128125
129126
// To disable the execution of a statment when it goes out of scope and wasn't used

hdr/sqlite_modern_cpp.h

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,15 @@ namespace sqlite {
7373
_stmt(std::move(other._stmt)),
7474
_inx(other._inx), execution_started(other.execution_started) { }
7575

76-
void reset() {
77-
sqlite3_reset(_stmt.get());
78-
sqlite3_clear_bindings(_stmt.get());
79-
_inx = 1;
80-
used(false);
81-
}
82-
8376
void execute() {
77+
_start_execute();
8478
int hresult;
85-
used(true); /* prevent from executing again when goes out of scope */
8679

8780
while((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {}
8881

8982
if(hresult != SQLITE_DONE) {
9083
errors::throw_sqlite_error(hresult, sql());
9184
}
92-
9385
}
9486

9587
std::string sql() {
@@ -107,8 +99,10 @@ namespace sqlite {
10799
}
108100

109101
void used(bool state) {
110-
if(execution_started == true && state == true) {
111-
throw errors::reexecution("Already used statement executed again! Please reset() first!",sql());
102+
if(!state) {
103+
// We may have to reset first if we haven't done so already:
104+
_next_index();
105+
--_inx;
112106
}
113107
execution_started = state;
114108
}
@@ -123,9 +117,22 @@ namespace sqlite {
123117

124118
bool execution_started = false;
125119

120+
int _next_index() {
121+
if(execution_started && !_inx) {
122+
sqlite3_reset(_stmt.get());
123+
sqlite3_clear_bindings(_stmt.get());
124+
}
125+
return ++_inx;
126+
}
127+
void _start_execute() {
128+
_next_index();
129+
_inx = 0;
130+
used(true);
131+
}
132+
126133
void _extract(std::function<void(void)> call_back) {
127134
int hresult;
128-
used(true);
135+
_start_execute();
129136

130137
while((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {
131138
call_back();
@@ -138,7 +145,7 @@ namespace sqlite {
138145

139146
void _extract_single_value(std::function<void(void)> call_back) {
140147
int hresult;
141-
used(true);
148+
_start_execute();
142149

143150
if((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {
144151
call_back();
@@ -243,13 +250,13 @@ namespace sqlite {
243250
database_binder(std::shared_ptr<sqlite3> db, std::u16string const & sql):
244251
_db(db),
245252
_stmt(_prepare(sql), sqlite3_finalize),
246-
_inx(1) {
253+
_inx(0) {
247254
}
248255

249256
database_binder(std::shared_ptr<sqlite3> db, std::string const & sql):
250257
_db(db),
251258
_stmt(_prepare(sql), sqlite3_finalize),
252-
_inx(1) {
259+
_inx(0) {
253260
}
254261

255262
~database_binder() noexcept(false) {
@@ -515,10 +522,9 @@ namespace sqlite {
515522
// int
516523
inline database_binder& operator<<(database_binder& db, const int& val) {
517524
int hresult;
518-
if((hresult = sqlite3_bind_int(db._stmt.get(), db._inx, val)) != SQLITE_OK) {
525+
if((hresult = sqlite3_bind_int(db._stmt.get(), db._next_index(), val)) != SQLITE_OK) {
519526
errors::throw_sqlite_error(hresult, db.sql());
520527
}
521-
++db._inx;
522528
return db;
523529
}
524530
inline void store_result_in_db(sqlite3_context* db, const int& val) {
@@ -542,11 +548,10 @@ namespace sqlite {
542548
// sqlite_int64
543549
inline database_binder& operator <<(database_binder& db, const sqlite_int64& val) {
544550
int hresult;
545-
if((hresult = sqlite3_bind_int64(db._stmt.get(), db._inx, val)) != SQLITE_OK) {
551+
if((hresult = sqlite3_bind_int64(db._stmt.get(), db._next_index(), val)) != SQLITE_OK) {
546552
errors::throw_sqlite_error(hresult, db.sql());
547553
}
548554

549-
++db._inx;
550555
return db;
551556
}
552557
inline void store_result_in_db(sqlite3_context* db, const sqlite_int64& val) {
@@ -570,11 +575,10 @@ namespace sqlite {
570575
// float
571576
inline database_binder& operator <<(database_binder& db, const float& val) {
572577
int hresult;
573-
if((hresult = sqlite3_bind_double(db._stmt.get(), db._inx, double(val))) != SQLITE_OK) {
578+
if((hresult = sqlite3_bind_double(db._stmt.get(), db._next_index(), double(val))) != SQLITE_OK) {
574579
errors::throw_sqlite_error(hresult, db.sql());
575580
}
576581

577-
++db._inx;
578582
return db;
579583
}
580584
inline void store_result_in_db(sqlite3_context* db, const float& val) {
@@ -598,11 +602,10 @@ namespace sqlite {
598602
// double
599603
inline database_binder& operator <<(database_binder& db, const double& val) {
600604
int hresult;
601-
if((hresult = sqlite3_bind_double(db._stmt.get(), db._inx, val)) != SQLITE_OK) {
605+
if((hresult = sqlite3_bind_double(db._stmt.get(), db._next_index(), val)) != SQLITE_OK) {
602606
errors::throw_sqlite_error(hresult, db.sql());
603607
}
604608

605-
++db._inx;
606609
return db;
607610
}
608611
inline void store_result_in_db(sqlite3_context* db, const double& val) {
@@ -628,10 +631,9 @@ namespace sqlite {
628631
void const* buf = reinterpret_cast<void const *>(vec.data());
629632
int bytes = vec.size() * sizeof(T);
630633
int hresult;
631-
if((hresult = sqlite3_bind_blob(db._stmt.get(), db._inx, buf, bytes, SQLITE_TRANSIENT)) != SQLITE_OK) {
634+
if((hresult = sqlite3_bind_blob(db._stmt.get(), db._next_index(), buf, bytes, SQLITE_TRANSIENT)) != SQLITE_OK) {
632635
errors::throw_sqlite_error(hresult, db.sql());
633636
}
634-
++db._inx;
635637
return db;
636638
}
637639
template<typename T, typename A> inline void store_result_in_db(sqlite3_context* db, const std::vector<T, A>& vec) {
@@ -661,10 +663,9 @@ namespace sqlite {
661663
/* for nullptr support */
662664
inline database_binder& operator <<(database_binder& db, std::nullptr_t) {
663665
int hresult;
664-
if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) {
666+
if((hresult = sqlite3_bind_null(db._stmt.get(), db._next_index())) != SQLITE_OK) {
665667
errors::throw_sqlite_error(hresult, db.sql());
666668
}
667-
++db._inx;
668669
return db;
669670
}
670671
inline void store_result_in_db(sqlite3_context* db, std::nullptr_t) {
@@ -723,11 +724,10 @@ namespace sqlite {
723724

724725
inline database_binder& operator <<(database_binder& db, const std::string& txt) {
725726
int hresult;
726-
if((hresult = sqlite3_bind_text(db._stmt.get(), db._inx, txt.data(), -1, SQLITE_TRANSIENT)) != SQLITE_OK) {
727+
if((hresult = sqlite3_bind_text(db._stmt.get(), db._next_index(), txt.data(), -1, SQLITE_TRANSIENT)) != SQLITE_OK) {
727728
errors::throw_sqlite_error(hresult, db.sql());
728729
}
729730

730-
++db._inx;
731731
return db;
732732
}
733733
inline void store_result_in_db(sqlite3_context* db, const std::string& val) {
@@ -754,11 +754,10 @@ namespace sqlite {
754754

755755
inline database_binder& operator <<(database_binder& db, const std::u16string& txt) {
756756
int hresult;
757-
if((hresult = sqlite3_bind_text16(db._stmt.get(), db._inx, txt.data(), -1, SQLITE_TRANSIENT)) != SQLITE_OK) {
757+
if((hresult = sqlite3_bind_text16(db._stmt.get(), db._next_index(), txt.data(), -1, SQLITE_TRANSIENT)) != SQLITE_OK) {
758758
errors::throw_sqlite_error(hresult, db.sql());
759759
}
760760

761-
++db._inx;
762761
return db;
763762
}
764763
inline void store_result_in_db(sqlite3_context* db, const std::u16string& val) {
@@ -794,11 +793,10 @@ namespace sqlite {
794793
return operator << (std::move(db), std::move(*val));
795794
}
796795
int hresult;
797-
if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) {
796+
if((hresult = sqlite3_bind_null(db._stmt.get(), db._next_index())) != SQLITE_OK) {
798797
errors::throw_sqlite_error(hresult, db.sql());
799798
}
800799

801-
++db._inx;
802800
return db;
803801
}
804802
template <typename OptionalT> inline void store_result_in_db(sqlite3_context* db, const std::optional<OptionalT>& val) {
@@ -835,11 +833,10 @@ namespace sqlite {
835833
return operator << (std::move(db), std::move(*val));
836834
}
837835
int hresult;
838-
if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) {
836+
if((hresult = sqlite3_bind_null(db._stmt.get(), db._next_index())) != SQLITE_OK) {
839837
errors::throw_sqlite_error(hresult, db.sql());
840838
}
841839

842-
++db._inx;
843840
return db;
844841
}
845842
template <typename BoostOptionalT> inline void store_result_in_db(sqlite3_context* db, const boost::optional<BoostOptionalT>& val) {
@@ -892,7 +889,7 @@ namespace sqlite {
892889
#endif
893890

894891
// Some ppl are lazy so we have a operator for proper prep. statemant handling.
895-
void inline operator++(database_binder& db, int) { db.execute(); db.reset(); }
892+
void inline operator++(database_binder& db, int) { db.execute(); }
896893

897894
// Convert the rValue binder to a reference and call first op<<, its needed for the call that creates the binder (be carefull of recursion here!)
898895
template<typename T> database_binder& operator << (database_binder&& db, const T& val) { return db << val; }

hdr/sqlite_modern_cpp/errors.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ namespace sqlite {
3737
//Some additional errors are here for the C++ interface
3838
class more_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
3939
class no_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
40-
class reexecution: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements need to be reset before calling them again
4140
class more_statements: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements can only contain one statement
4241

4342
static void throw_sqlite_error(const int& error_code, const std::string &sql = "") {

tests/prepared_statment.cc

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,8 @@ int main() {
1616

1717
pps >> test; // execute statement
1818

19-
pps.reset();
20-
2119
pps << 4; // bind a rvalue
22-
pps++; // and execute and reset
20+
pps++; // and execute
2321

2422
pps << 8 >> test;
2523

@@ -81,22 +79,9 @@ int main() {
8179
auto prep = db << "select ?";
8280

8381
prep << 5;
84-
8582
prep.execute();
86-
try {
87-
prep.execute();
88-
exit(EXIT_FAILURE);
89-
} catch(errors::reexecution& ex) {
90-
// Thats ok here
91-
} catch(...) {
92-
exit(EXIT_FAILURE);
93-
}
94-
95-
prep.reset();
96-
9783
prep << 6;
9884
prep.execute();
99-
10085
}
10186

10287

0 commit comments

Comments
 (0)