diff --git a/README.md b/README.md index f01f59f5..39920769 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index b493aaa2..c553d278 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -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() { @@ -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; } @@ -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 call_back) { int hresult; - used(true); + _start_execute(); while((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) { call_back(); @@ -138,7 +145,7 @@ namespace sqlite { void _extract_single_value(std::function call_back) { int hresult; - used(true); + _start_execute(); if((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) { call_back(); @@ -243,13 +250,13 @@ namespace sqlite { database_binder(std::shared_ptr db, std::u16string const & sql): _db(db), _stmt(_prepare(sql), sqlite3_finalize), - _inx(1) { + _inx(0) { } database_binder(std::shared_ptr db, std::string const & sql): _db(db), _stmt(_prepare(sql), sqlite3_finalize), - _inx(1) { + _inx(0) { } ~database_binder() noexcept(false) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -628,10 +631,9 @@ namespace sqlite { void const* buf = reinterpret_cast(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 inline void store_result_in_db(sqlite3_context* db, const std::vector& vec) { @@ -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) { @@ -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) { @@ -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) { @@ -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 inline void store_result_in_db(sqlite3_context* db, const std::optional& val) { @@ -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 inline void store_result_in_db(sqlite3_context* db, const boost::optional& val) { @@ -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 database_binder& operator << (database_binder&& db, const T& val) { return db << val; } diff --git a/hdr/sqlite_modern_cpp/errors.h b/hdr/sqlite_modern_cpp/errors.h index 60faaecc..6c75b7ae 100644 --- a/hdr/sqlite_modern_cpp/errors.h +++ b/hdr/sqlite_modern_cpp/errors.h @@ -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 = "") { diff --git a/tests/prepared_statment.cc b/tests/prepared_statment.cc index b50d356d..8080f0ca 100644 --- a/tests/prepared_statment.cc +++ b/tests/prepared_statment.cc @@ -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; @@ -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(); - }