From 2df66f1147864a62bfa19f358dfe02b766830d29 Mon Sep 17 00:00:00 2001 From: Jan-Wilke Date: Wed, 22 Feb 2017 15:05:11 +0100 Subject: [PATCH 1/3] Fixed reexecution of statements #97 - Used getter setter for all uses of execution_started - removed reset() call from _extract* - added exception for reexecution of already used statment --- hdr/sqlite_modern_cpp.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index e46ba76a..470f86ad 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -150,13 +150,14 @@ namespace sqlite { void 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) { exceptions::throw_sqlite_error(hresult, sql()); } - used(true); /* prevent from executing again when goes out of scope */ + } std::string sql() { @@ -173,7 +174,12 @@ namespace sqlite { return sqlite3_sql(_stmt.get()); } - void used(bool state) { execution_started = state; } + void used(bool state) { + if(execution_started == true && state == true) { + throw sqlite_exception("Already used statement executed again! Please reset() first!",sql()); + } + execution_started = state; + } bool used() const { return execution_started; } private: @@ -186,8 +192,8 @@ namespace sqlite { bool execution_started = false; void _extract(std::function call_back) { - execution_started = true; int hresult; + used(true); while((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) { call_back(); @@ -196,12 +202,11 @@ namespace sqlite { if(hresult != SQLITE_DONE) { exceptions::throw_sqlite_error(hresult, sql()); } - reset(); } void _extract_single_value(std::function call_back) { - execution_started = true; int hresult; + used(true); if((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) { call_back(); @@ -216,7 +221,6 @@ namespace sqlite { if(hresult != SQLITE_DONE) { exceptions::throw_sqlite_error(hresult, sql()); } - reset(); } #ifdef _MSC_VER @@ -307,7 +311,7 @@ namespace sqlite { ~database_binder() noexcept(false) { /* Will be executed if no >>op is found, but not if an exception is in mid flight */ - if(!execution_started && !_has_uncaught_exception && _stmt) { + if(!used() && !_has_uncaught_exception && _stmt) { execute(); } } From a42770e1486cab24454d73c2faf7327822e79938 Mon Sep 17 00:00:00 2001 From: Jan-Wilke Date: Wed, 22 Feb 2017 15:12:42 +0100 Subject: [PATCH 2/3] Updated Test to check for exception --- tests/prepared_statment.cc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/prepared_statment.cc b/tests/prepared_statment.cc index ea447371..4d60a4da 100644 --- a/tests/prepared_statment.cc +++ b/tests/prepared_statment.cc @@ -75,6 +75,28 @@ int main() { (pps4 << test << test << test)++; } + { + auto prep = db << "select ?"; + + prep << 5; + + prep.execute(); + try { + prep.execute(); + } catch(sqlite_exception& ex) { + cout << ex.what() << " " << ex.get_sql() << "\n"; + if(std::string(ex.what()) != "Already used statement executed again! Please reset() first!") { + exit(EXIT_FAILURE); + } + } + + prep.reset(); + + prep << 6; + prep.execute(); + + } + } catch(sqlite_exception e) { cout << "Unexpected error " << e.what() << endl; From 16907b07eeb86c1009c6db9e7d7af70a3896ff40 Mon Sep 17 00:00:00 2001 From: Jan-Wilke Date: Wed, 22 Feb 2017 16:50:28 +0100 Subject: [PATCH 3/3] Added custom exception class for reexecution and brought test inline with README --- hdr/sqlite_modern_cpp.h | 3 ++- tests/prepared_statment.cc | 16 +++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index 470f86ad..3898769c 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -78,6 +78,7 @@ 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 static void throw_sqlite_error(const int& error_code, const std::string &sql = "") { if(error_code == SQLITE_ERROR) throw exceptions::error(error_code, sql); @@ -176,7 +177,7 @@ namespace sqlite { void used(bool state) { if(execution_started == true && state == true) { - throw sqlite_exception("Already used statement executed again! Please reset() first!",sql()); + throw exceptions::reexecution("Already used statement executed again! Please reset() first!",sql()); } execution_started = state; } diff --git a/tests/prepared_statment.cc b/tests/prepared_statment.cc index 4d60a4da..5cd63882 100644 --- a/tests/prepared_statment.cc +++ b/tests/prepared_statment.cc @@ -14,10 +14,12 @@ int main() { int test = 4; pps << test; // set a bound var - pps >> test; // execute and reset statment + pps >> test; // execute statement + + pps.reset(); pps << 4; // bind a rvalue - pps >> test; // and execute again + pps++; // and execute and reset pps << 8 >> test; @@ -83,11 +85,11 @@ int main() { prep.execute(); try { prep.execute(); - } catch(sqlite_exception& ex) { - cout << ex.what() << " " << ex.get_sql() << "\n"; - if(std::string(ex.what()) != "Already used statement executed again! Please reset() first!") { - exit(EXIT_FAILURE); - } + exit(EXIT_FAILURE); + } catch(exceptions::reexecution& ex) { + // Thats ok here + } catch(...) { + exit(EXIT_FAILURE); } prep.reset();