Skip to content

Auto reset after statement execution #120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,10 @@ ps << tmp;
// But beware that it will execute on destruction if it wasn't executed!
ps >> [&](int a,int b){ ... };

// after a successfull execution the statment needs to be reset to be execute again. This will reset the bound values too!
ps.reset();

// after a successfull execution the statment can be executed again, but the bound values are resetted.
// If you dont need the returned values you can execute it like this
ps.execute(); // the statment will not be reset!

// there is a convinience operator to execute and reset in one go
ps.execute();
// or like this
ps++;

// To disable the execution of a statment when it goes out of scope and wasn't used
Expand Down
69 changes: 33 additions & 36 deletions hdr/sqlite_modern_cpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,23 +73,15 @@ namespace sqlite {
_stmt(std::move(other._stmt)),
_inx(other._inx), execution_started(other.execution_started) { }

void reset() {
sqlite3_reset(_stmt.get());
sqlite3_clear_bindings(_stmt.get());
_inx = 1;
used(false);
}

void execute() {
_start_execute();
int hresult;
used(true); /* prevent from executing again when goes out of scope */

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

if(hresult != SQLITE_DONE) {
errors::throw_sqlite_error(hresult, sql());
}

}

std::string sql() {
Expand All @@ -107,8 +99,10 @@ namespace sqlite {
}

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

bool execution_started = false;

int _next_index() {
if(execution_started && !_inx) {
sqlite3_reset(_stmt.get());
sqlite3_clear_bindings(_stmt.get());
}
return ++_inx;
}
void _start_execute() {
_next_index();
_inx = 0;
used(true);
}

void _extract(std::function<void(void)> call_back) {
int hresult;
used(true);
_start_execute();

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

void _extract_single_value(std::function<void(void)> call_back) {
int hresult;
used(true);
_start_execute();

if((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {
call_back();
Expand Down Expand Up @@ -243,13 +250,13 @@ namespace sqlite {
database_binder(std::shared_ptr<sqlite3> db, std::u16string const & sql):
_db(db),
_stmt(_prepare(sql), sqlite3_finalize),
_inx(1) {
_inx(0) {
}

database_binder(std::shared_ptr<sqlite3> db, std::string const & sql):
_db(db),
_stmt(_prepare(sql), sqlite3_finalize),
_inx(1) {
_inx(0) {
}

~database_binder() noexcept(false) {
Expand Down Expand Up @@ -515,10 +522,9 @@ namespace sqlite {
// int
inline database_binder& operator<<(database_binder& db, const int& val) {
int hresult;
if((hresult = sqlite3_bind_int(db._stmt.get(), db._inx, val)) != SQLITE_OK) {
if((hresult = sqlite3_bind_int(db._stmt.get(), db._next_index(), val)) != SQLITE_OK) {
errors::throw_sqlite_error(hresult, db.sql());
}
++db._inx;
return db;
}
inline void store_result_in_db(sqlite3_context* db, const int& val) {
Expand All @@ -542,11 +548,10 @@ namespace sqlite {
// sqlite_int64
inline database_binder& operator <<(database_binder& db, const sqlite_int64& val) {
int hresult;
if((hresult = sqlite3_bind_int64(db._stmt.get(), db._inx, val)) != SQLITE_OK) {
if((hresult = sqlite3_bind_int64(db._stmt.get(), db._next_index(), val)) != SQLITE_OK) {
errors::throw_sqlite_error(hresult, db.sql());
}

++db._inx;
return db;
}
inline void store_result_in_db(sqlite3_context* db, const sqlite_int64& val) {
Expand All @@ -570,11 +575,10 @@ namespace sqlite {
// float
inline database_binder& operator <<(database_binder& db, const float& val) {
int hresult;
if((hresult = sqlite3_bind_double(db._stmt.get(), db._inx, double(val))) != SQLITE_OK) {
if((hresult = sqlite3_bind_double(db._stmt.get(), db._next_index(), double(val))) != SQLITE_OK) {
errors::throw_sqlite_error(hresult, db.sql());
}

++db._inx;
return db;
}
inline void store_result_in_db(sqlite3_context* db, const float& val) {
Expand All @@ -598,11 +602,10 @@ namespace sqlite {
// double
inline database_binder& operator <<(database_binder& db, const double& val) {
int hresult;
if((hresult = sqlite3_bind_double(db._stmt.get(), db._inx, val)) != SQLITE_OK) {
if((hresult = sqlite3_bind_double(db._stmt.get(), db._next_index(), val)) != SQLITE_OK) {
errors::throw_sqlite_error(hresult, db.sql());
}

++db._inx;
return db;
}
inline void store_result_in_db(sqlite3_context* db, const double& val) {
Expand All @@ -628,10 +631,9 @@ namespace sqlite {
void const* buf = reinterpret_cast<void const *>(vec.data());
int bytes = vec.size() * sizeof(T);
int hresult;
if((hresult = sqlite3_bind_blob(db._stmt.get(), db._inx, buf, bytes, SQLITE_TRANSIENT)) != SQLITE_OK) {
if((hresult = sqlite3_bind_blob(db._stmt.get(), db._next_index(), buf, bytes, SQLITE_TRANSIENT)) != SQLITE_OK) {
errors::throw_sqlite_error(hresult, db.sql());
}
++db._inx;
return db;
}
template<typename T, typename A> inline void store_result_in_db(sqlite3_context* db, const std::vector<T, A>& vec) {
Expand Down Expand Up @@ -661,10 +663,9 @@ namespace sqlite {
/* for nullptr support */
inline database_binder& operator <<(database_binder& db, std::nullptr_t) {
int hresult;
if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) {
if((hresult = sqlite3_bind_null(db._stmt.get(), db._next_index())) != SQLITE_OK) {
errors::throw_sqlite_error(hresult, db.sql());
}
++db._inx;
return db;
}
inline void store_result_in_db(sqlite3_context* db, std::nullptr_t) {
Expand Down Expand Up @@ -723,11 +724,10 @@ namespace sqlite {

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

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

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

++db._inx;
return db;
}
inline void store_result_in_db(sqlite3_context* db, const std::u16string& val) {
Expand Down Expand Up @@ -794,11 +793,10 @@ namespace sqlite {
return operator << (std::move(db), std::move(*val));
}
int hresult;
if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) {
if((hresult = sqlite3_bind_null(db._stmt.get(), db._next_index())) != SQLITE_OK) {
errors::throw_sqlite_error(hresult, db.sql());
}

++db._inx;
return db;
}
template <typename OptionalT> inline void store_result_in_db(sqlite3_context* db, const std::optional<OptionalT>& val) {
Expand Down Expand Up @@ -835,11 +833,10 @@ namespace sqlite {
return operator << (std::move(db), std::move(*val));
}
int hresult;
if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) {
if((hresult = sqlite3_bind_null(db._stmt.get(), db._next_index())) != SQLITE_OK) {
errors::throw_sqlite_error(hresult, db.sql());
}

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

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

// 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!)
template<typename T> database_binder& operator << (database_binder&& db, const T& val) { return db << val; }
Expand Down
1 change: 0 additions & 1 deletion hdr/sqlite_modern_cpp/errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ namespace sqlite {
//Some additional errors are here for the C++ interface
class more_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
class no_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
class reexecution: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements need to be reset before calling them again
class more_statements: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements can only contain one statement

static void throw_sqlite_error(const int& error_code, const std::string &sql = "") {
Expand Down
17 changes: 1 addition & 16 deletions tests/prepared_statment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ int main() {

pps >> test; // execute statement

pps.reset();

pps << 4; // bind a rvalue
pps++; // and execute and reset
pps++; // and execute

pps << 8 >> test;

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

prep << 5;

prep.execute();
try {
prep.execute();
exit(EXIT_FAILURE);
} catch(errors::reexecution& ex) {
// Thats ok here
} catch(...) {
exit(EXIT_FAILURE);
}

prep.reset();

prep << 6;
prep.execute();

}


Expand Down