From 0312f0d8d2065d553673d1c9bfd9d4954b103501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Tue, 25 Apr 2017 15:56:18 +0200 Subject: [PATCH 1/7] Second try for error logging --- hdr/sqlite_modern_cpp/log.h | 70 +++++++++++++++++++++++++++++++++++++ tests/error_log.cc | 38 ++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 hdr/sqlite_modern_cpp/log.h create mode 100644 tests/error_log.cc diff --git a/hdr/sqlite_modern_cpp/log.h b/hdr/sqlite_modern_cpp/log.h new file mode 100644 index 00000000..ed0582c6 --- /dev/null +++ b/hdr/sqlite_modern_cpp/log.h @@ -0,0 +1,70 @@ +#include "errors.h" + +#include + +#include +#include +#include + +namespace sqlite { + namespace detail { + template + class FunctorOverload: public Functor, public FunctorOverload { + public: + template + FunctorOverload(Functor1 &&functor, Remaining &&... remaining): + Functor(std::forward(functor)), + FunctorOverload(std::forward(remaining)...) {} + using Functor::operator(); + using FunctorOverload::operator(); + }; + template + class FunctorOverload: public Functor { + public: + template + FunctorOverload(Functor1 &&functor): + Functor(std::forward(functor)) {} + using Functor::operator(); + }; + } + template + typename std::enable_if::value>::type + error_log(Handler &&handler); + template + typename std::enable_if::value>::type + error_log(Handler &&handler); + template + typename std::enable_if=2>::type + error_log(Handler &&...handler) { + return error_log(detail::FunctorOverload::type...>(std::forward(handler)...)); + } + template + typename std::enable_if::value>::type + error_log(Handler &&handler) { + return error_log(std::forward(handler), [](const sqlite_exception&) {}); + } + template + typename std::enable_if::value>::type + error_log(Handler &&handler) { + auto ptr = new auto([handler = std::forward(handler)](int error_code, const char *errstr) mutable { + switch(error_code & 0xFF) { +#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \ + case SQLITE_ ## NAME: switch(error_code) { \ + derived \ + default: handler(errors::name(errstr, "", error_code)); \ + };break; +#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \ + case SQLITE_ ## BASE ## _ ## SUB: \ + handler(errors::base ## _ ## sub(errstr, "", error_code)); \ + break; +#include "lists/error_codes.h" +#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED +#undef SQLITE_MODERN_CPP_ERROR_CODE + default: handler(sqlite_exception(errstr, "", error_code)); \ + } + }); + sqlite3_config(SQLITE_CONFIG_LOG, (void(*)(void*,int,const char*))[](void *functor, int error_code, const char *errstr) { + (*static_cast(functor))(error_code, errstr); + }, ptr); + } +} diff --git a/tests/error_log.cc b/tests/error_log.cc new file mode 100644 index 00000000..d59cf08c --- /dev/null +++ b/tests/error_log.cc @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include +#include +using namespace sqlite; +using namespace std; + + +int main() { + bool error_detected = false; + error_log( + [&](errors::constraint) { + cerr << "Wrong error detected!" << endl; + }, + [&](errors::constraint_primarykey e) { + cerr << e.get_code() << '/' << e.get_extended_code() << ": " << e.what() << endl; + error_detected = true; + } + ); + database db(":memory:"); + db << "CREATE TABLE person (id integer primary key not null, name TEXT);"; + + try { + db << "INSERT INTO person (id,name) VALUES (?,?)" << 1 << "jack"; + // inserting again to produce error + db << "INSERT INTO person (id,name) VALUES (?,?)" << 1 << "jack"; + } catch (errors::constraint& e) { + } + + if(!error_detected) { + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); +} From cb29f139cf4bd78a3202680313b4e1f1868252c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Tue, 25 Apr 2017 16:13:41 +0200 Subject: [PATCH 2/7] Fix for function pointers --- hdr/sqlite_modern_cpp/log.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/hdr/sqlite_modern_cpp/log.h b/hdr/sqlite_modern_cpp/log.h index ed0582c6..6cf32c0a 100644 --- a/hdr/sqlite_modern_cpp/log.h +++ b/hdr/sqlite_modern_cpp/log.h @@ -26,6 +26,21 @@ namespace sqlite { Functor(std::forward(functor)) {} using Functor::operator(); }; + template + class WrapIntoFunctor: public Functor { + public: + template + WrapIntoFunctor(Functor1 &&functor): + Functor(std::forward(functor)) {} + using Functor::operator(); + }; + template + class WrapIntoFunctor { + ReturnType(*ptr)(Arguments...); + public: + WrapIntoFunctor(ReturnType(*ptr)(Arguments...)): ptr(ptr) {} + ReturnType operator()(Arguments... arguments) { return (*ptr)(std::forward(arguments)...); } + }; } template typename std::enable_if::value>::type @@ -36,7 +51,7 @@ namespace sqlite { template typename std::enable_if=2>::type error_log(Handler &&...handler) { - return error_log(detail::FunctorOverload::type...>(std::forward(handler)...)); + return error_log(detail::FunctorOverload::type>...>(std::forward(handler)...)); } template typename std::enable_if::value>::type From c03d4c808ed78dff97be94fe3c5c8b38d5605f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Tue, 25 Apr 2017 17:49:48 +0200 Subject: [PATCH 3/7] Fix for C++14 --- hdr/sqlite_modern_cpp/log.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hdr/sqlite_modern_cpp/log.h b/hdr/sqlite_modern_cpp/log.h index 6cf32c0a..0e897400 100644 --- a/hdr/sqlite_modern_cpp/log.h +++ b/hdr/sqlite_modern_cpp/log.h @@ -8,6 +8,12 @@ namespace sqlite { namespace detail { + template + using void_t = void; + template + struct is_callable : std::false_type {}; + template + struct is_callable()(std::declval()...))>> : std::true_type {}; template class FunctorOverload: public Functor, public FunctorOverload { public: @@ -43,10 +49,10 @@ namespace sqlite { }; } template - typename std::enable_if::value>::type + typename std::enable_if::value>::type error_log(Handler &&handler); template - typename std::enable_if::value>::type + typename std::enable_if::value>::type error_log(Handler &&handler); template typename std::enable_if=2>::type @@ -54,12 +60,12 @@ namespace sqlite { return error_log(detail::FunctorOverload::type>...>(std::forward(handler)...)); } template - typename std::enable_if::value>::type + typename std::enable_if::value>::type error_log(Handler &&handler) { return error_log(std::forward(handler), [](const sqlite_exception&) {}); } template - typename std::enable_if::value>::type + typename std::enable_if::value>::type error_log(Handler &&handler) { auto ptr = new auto([handler = std::forward(handler)](int error_code, const char *errstr) mutable { switch(error_code & 0xFF) { From 7271dff66f4566a97983fa4d195983c75aa7241f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Tue, 25 Apr 2017 19:16:08 +0200 Subject: [PATCH 4/7] Fix memory leak --- hdr/sqlite_modern_cpp/log.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/hdr/sqlite_modern_cpp/log.h b/hdr/sqlite_modern_cpp/log.h index 0e897400..a8f7be22 100644 --- a/hdr/sqlite_modern_cpp/log.h +++ b/hdr/sqlite_modern_cpp/log.h @@ -47,6 +47,14 @@ namespace sqlite { WrapIntoFunctor(ReturnType(*ptr)(Arguments...)): ptr(ptr) {} ReturnType operator()(Arguments... arguments) { return (*ptr)(std::forward(arguments)...); } }; + inline void store_error_log_data_pointer(std::shared_ptr ptr) { + static std::shared_ptr stored; + stored = std::move(ptr); + } + template + std::shared_ptr::type> make_shared_inferred(T &&t) { + return std::make_shared::type>(std::forward(t)); + } } template typename std::enable_if::value>::type @@ -67,7 +75,7 @@ namespace sqlite { template typename std::enable_if::value>::type error_log(Handler &&handler) { - auto ptr = new auto([handler = std::forward(handler)](int error_code, const char *errstr) mutable { + auto ptr = detail::make_shared_inferred([handler = std::forward(handler)](int error_code, const char *errstr) mutable { switch(error_code & 0xFF) { #define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \ case SQLITE_ ## NAME: switch(error_code) { \ @@ -84,8 +92,10 @@ namespace sqlite { default: handler(sqlite_exception(errstr, "", error_code)); \ } }); + sqlite3_config(SQLITE_CONFIG_LOG, (void(*)(void*,int,const char*))[](void *functor, int error_code, const char *errstr) { - (*static_cast(functor))(error_code, errstr); - }, ptr); + (*static_cast(functor))(error_code, errstr); + }, ptr.get()); + detail::store_error_log_data_pointer(std::move(ptr)); } } From 2f8061f6f212df6b587dbc52af701121f7c05200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Wed, 26 Apr 2017 22:12:47 +0200 Subject: [PATCH 5/7] Add documentation --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index ade74e00..d5db350b 100644 --- a/README.md +++ b/README.md @@ -402,6 +402,30 @@ Additionally you can use `get_sql()` to see the SQL statement leading to the err catch(sqlite::errors::constraint_primarykey e) { } */ ``` +You can also register a error logging function with `sqlite::error_log`. +The `` header has to be included to make this function available. +The call to `sqlite::error_log` has to be the first call to any `sqlite_modern_cpp` function by your program. + +```c++ + error_log( + [&](sqlite_exception& e) { + cerr << e.get_code() << ": " << e.what() << endl; + }, + [&](errors::misuse& e) { + /* You can behave differently to specific exceptions */ + } + ); + database db(":memory:"); + db << "create table person (id integer primary key not null, name text);"; + + try { + db << "insert into person (id, name) values (?,?)" << 1 << "jack"; + // inserting again to produce error + db << "insert into person (id, name) values (?,?)" << 1 << "jack"; + } + catch (sqlite_exception& e) {} +``` + Custom SQL functions ---- From 268a3cb939fa5ba144eefd470009ce66c9a03dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Wed, 26 Apr 2017 22:29:40 +0200 Subject: [PATCH 6/7] Add additional test --- tests/error_log2.cc | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/error_log2.cc diff --git a/tests/error_log2.cc b/tests/error_log2.cc new file mode 100644 index 00000000..fc0a5bdc --- /dev/null +++ b/tests/error_log2.cc @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include +#include +using namespace sqlite; +using namespace std; + + +int main() { + bool error_detected = false; + error_log( + [&](errors::constraint e) { + cerr << e.get_code() << '/' << e.get_extended_code() << ": " << e.what() << endl; + error_detected = true; + } + ); + database db(":memory:"); + db << "CREATE TABLE person (id integer primary key not null, name TEXT);"; + + try { + db << "INSERT INTO person (id,name) VALUES (?,?)" << 1 << "jack"; + // inserting again to produce error + db << "INSERT INTO person (id,name) VALUES (?,?)" << 1 << "jack"; + } catch (errors::constraint& e) { + } + + if(!error_detected) { + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); +} From 317e2e1b029d0905d927ff2945f7ab2f173ca8cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Wed, 10 May 2017 18:20:58 +0200 Subject: [PATCH 7/7] Fix misleading comment --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d5db350b..6c45471b 100644 --- a/README.md +++ b/README.md @@ -412,7 +412,7 @@ The call to `sqlite::error_log` has to be the first call to any `sqlite_modern_c cerr << e.get_code() << ": " << e.what() << endl; }, [&](errors::misuse& e) { - /* You can behave differently to specific exceptions */ + /* You can behave differently to specific errors */ } ); database db(":memory:");