From 64c40af72f6b689ce83ca0a0f664f409d2d4e43a Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 15 Jun 2018 11:21:19 -0600 Subject: [PATCH 01/21] C++17 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 82b80baa..217f726b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ OPTION(ENABLE_SQLCIPHER_TESTS "enable sqlchipher test") # Creates the file compile_commands.json in the build directory. SET(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set (CMAKE_CXX_STANDARD 14) +set (CMAKE_CXX_STANDARD 17) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") include("cmake/HunterGate.cmake") From 2f2e7d82094902d97c31d05c78d558d17b1fe566 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 15 Jun 2018 11:45:16 -0600 Subject: [PATCH 02/21] Fix compilation on MSVC/Windows --- hdr/sqlite_modern_cpp/log.h | 4 ++-- tests/flags.cc | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/hdr/sqlite_modern_cpp/log.h b/hdr/sqlite_modern_cpp/log.h index a8f7be22..5abe2933 100644 --- a/hdr/sqlite_modern_cpp/log.h +++ b/hdr/sqlite_modern_cpp/log.h @@ -93,9 +93,9 @@ namespace sqlite { } }); - sqlite3_config(SQLITE_CONFIG_LOG, (void(*)(void*,int,const char*))[](void *functor, int error_code, const char *errstr) { + sqlite3_config(SQLITE_CONFIG_LOG, static_cast([](void *functor, int error_code, const char *errstr) { (*static_cast(functor))(error_code, errstr); - }, ptr.get()); + }), ptr.get()); detail::store_error_log_data_pointer(std::move(ptr)); } } diff --git a/tests/flags.cc b/tests/flags.cc index 69b06641..44543151 100644 --- a/tests/flags.cc +++ b/tests/flags.cc @@ -13,8 +13,9 @@ struct TmpFile { TmpFile(): fname("./flags.db") { } ~TmpFile() { remove(fname.c_str()); } }; - -#if BYTE_ORDER == BIG_ENDIAN +#ifdef _WIN32 +#define OUR_UTF16 "UTF-16le" +#elif BYTE_ORDER == BIG_ENDIAN #define OUR_UTF16 "UTF-16be" #else #define OUR_UTF16 "UTF-16le" From 5515487ae2b01846ec310eb82b27d23ee1a7ac1f Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 15 Jun 2018 14:38:21 -0600 Subject: [PATCH 03/21] Fix Modern C++ detection on MSVC --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 217f726b..b96bde0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ else() endif() catch_discover_tests(tests) +target_compile_options(tests PUBLIC $<$:/Zc:__cplusplus> ) # Place the file in the source directory, permitting us to place a single configuration file for YCM there. # YCM is the code-completion engine for (neo)vim https://github.com/Valloric/YouCompleteMe From fd3f0bfffc8f9ad80e13ffb6cc84e298348db96f Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 15 Jun 2018 14:56:54 -0600 Subject: [PATCH 04/21] String_view arguments instead of string --- hdr/sqlite_modern_cpp.h | 44 ++++++++++++++++------------ hdr/sqlite_modern_cpp/errors.h | 8 ++--- hdr/sqlite_modern_cpp/type_wrapper.h | 28 ++++++++++-------- 3 files changed, 45 insertions(+), 35 deletions(-) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index 964f993c..2ac6b6f7 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -42,7 +42,7 @@ namespace sqlite { void execute(); - std::string sql() { + std::string_view sql() { #if SQLITE_VERSION_NUMBER >= 3014000 auto sqlite_deleter = [](void *ptr) {sqlite3_free(ptr);}; std::unique_ptr str(sqlite3_expanded_sql(_stmt.get()), sqlite_deleter); @@ -52,7 +52,7 @@ namespace sqlite { #endif } - std::string original_sql() { + std::string_view original_sql() { return sqlite3_sql(_stmt.get()); } @@ -85,11 +85,19 @@ namespace sqlite { return ++_inx; } - sqlite3_stmt* _prepare(const std::u16string& sql) { - return _prepare(utility::utf16_to_utf8(sql)); + sqlite3_stmt* _prepare(const std::u16string_view& sql) { + //return _prepare(utility::utf16_to_utf8(sql)); + int hresult; + sqlite3_stmt* tmp = nullptr; + const void *remaining; + hresult = sqlite3_prepare16_v2(_db.get(), sql.data(), -1, &tmp, &remaining); + if (hresult != SQLITE_OK) errors::throw_sqlite_error(hresult, utility::utf16_to_utf8(sql.data())); + if (!std::all_of(static_cast(remaining), sql.data() + sql.size(), [](char16_t ch) {return std::isspace(ch); })) + throw errors::more_statements("Multiple semicolon separated statements are unsupported", utility::utf16_to_utf8(sql.data())); + return tmp; } - sqlite3_stmt* _prepare(const std::string& sql) { + sqlite3_stmt* _prepare(const std::string_view& sql) { int hresult; sqlite3_stmt* tmp = nullptr; const char *remaining; @@ -105,13 +113,13 @@ namespace sqlite { public: - database_binder(std::shared_ptr db, std::u16string const & sql): + database_binder(std::shared_ptr db, std::u16string_view const & sql): _db(db), _stmt(_prepare(sql), sqlite3_finalize), _inx(0) { } - database_binder(std::shared_ptr db, std::string const & sql): + database_binder(std::shared_ptr db, std::string_view const & sql): _db(db), _stmt(_prepare(sql), sqlite3_finalize), _inx(0) { @@ -362,7 +370,7 @@ namespace sqlite { std::shared_ptr _db; public: - database(const std::string &db_name, const sqlite_config &config = {}): _db(nullptr) { + database(const std::string_view &db_name, const sqlite_config &config = {}): _db(nullptr) { sqlite3* tmp = nullptr; auto ret = sqlite3_open_v2(db_name.data(), &tmp, static_cast(config.flags), config.zVfs); _db = std::shared_ptr(tmp, [=](sqlite3* ptr) { sqlite3_close_v2(ptr); }); // this will close the connection eventually when no longer needed. @@ -372,8 +380,8 @@ namespace sqlite { *this << R"(PRAGMA encoding = "UTF-16";)"; } - database(const std::u16string &db_name, const sqlite_config &config = {}): _db(nullptr) { - auto db_name_utf8 = utility::utf16_to_utf8(db_name); + database(const std::u16string_view &db_name, const sqlite_config &config = {}): _db(nullptr) { + auto db_name_utf8 = utility::utf16_to_utf8(db_name.data()); sqlite3* tmp = nullptr; auto ret = sqlite3_open_v2(db_name_utf8.data(), &tmp, static_cast(config.flags), config.zVfs); _db = std::shared_ptr(tmp, [=](sqlite3* ptr) { sqlite3_close_v2(ptr); }); // this will close the connection eventually when no longer needed. @@ -386,20 +394,20 @@ namespace sqlite { database(std::shared_ptr db): _db(db) {} - database_binder operator<<(const std::string& sql) { + database_binder operator<<(const std::string_view& sql) { return database_binder(_db, sql); } database_binder operator<<(const char* sql) { - return *this << std::string(sql); + return *this << std::string_view(sql); } - database_binder operator<<(const std::u16string& sql) { + database_binder operator<<(const std::u16string_view& sql) { return database_binder(_db, sql); } database_binder operator<<(const char16_t* sql) { - return *this << std::u16string(sql); + return *this << std::u16string_view(sql); } connection_type connection() const { return _db; } @@ -413,12 +421,12 @@ namespace sqlite { } template - void define(const std::string &name, Function&& func) { + void define(const std::string_view &name, Function&& func) { typedef utility::function_traits traits; auto funcPtr = new auto(std::forward(func)); if(int result = sqlite3_create_function_v2( - _db.get(), name.c_str(), traits::arity, SQLITE_UTF8, funcPtr, + _db.get(), name.data(), traits::arity, SQLITE_UTF8, funcPtr, sql_function_binder::scalar::type>, nullptr, nullptr, [](void* ptr){ delete static_cast(ptr); @@ -427,13 +435,13 @@ namespace sqlite { } template - void define(const std::string &name, StepFunction&& step, FinalFunction&& final) { + void define(const std::string_view &name, StepFunction&& step, FinalFunction&& final) { typedef utility::function_traits traits; using ContextType = typename std::remove_reference>::type; auto funcPtr = new auto(std::make_pair(std::forward(step), std::forward(final))); if(int result = sqlite3_create_function_v2( - _db.get(), name.c_str(), traits::arity - 1, SQLITE_UTF8, funcPtr, nullptr, + _db.get(), name.data(), traits::arity - 1, SQLITE_UTF8, funcPtr, nullptr, sql_function_binder::step::type>, sql_function_binder::final::type>, [](void* ptr){ diff --git a/hdr/sqlite_modern_cpp/errors.h b/hdr/sqlite_modern_cpp/errors.h index cc25ae97..c22b5c0c 100644 --- a/hdr/sqlite_modern_cpp/errors.h +++ b/hdr/sqlite_modern_cpp/errors.h @@ -9,11 +9,11 @@ namespace sqlite { class sqlite_exception: public std::runtime_error { public: - sqlite_exception(const char* msg, std::string sql, int code = -1): runtime_error(msg), code(code), sql(sql) {} - sqlite_exception(int code, std::string sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {} + sqlite_exception(const char* msg, std::string_view sql, int code = -1): runtime_error(msg), code(code), sql(sql) {} + sqlite_exception(int code, std::string_view sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {} int get_code() const {return code & 0xFF;} int get_extended_code() const {return code;} - std::string get_sql() const {return sql;} + std::string_view get_sql() const {return sql;} private: int code; std::string sql; @@ -40,7 +40,7 @@ namespace sqlite { class more_statements: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements can only contain one statement class invalid_utf16: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - static void throw_sqlite_error(const int& error_code, const std::string &sql = "") { + static void throw_sqlite_error(const int& error_code, const std::string_view &sql = "") { switch(error_code & 0xFF) { #define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \ case SQLITE_ ## NAME: switch(error_code) { \ diff --git a/hdr/sqlite_modern_cpp/type_wrapper.h b/hdr/sqlite_modern_cpp/type_wrapper.h index 375f8d0f..9ba7aeaa 100644 --- a/hdr/sqlite_modern_cpp/type_wrapper.h +++ b/hdr/sqlite_modern_cpp/type_wrapper.h @@ -150,16 +150,17 @@ namespace sqlite { sqlite3_result_null(db); } - // std::string + // std::string_view + template<> + struct has_sqlite_type : std::true_type {}; template<> struct has_sqlite_type : std::true_type {}; - - inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::string& val) { + inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::string_view& val) { return sqlite3_bind_text(stmt, inx, val.data(), -1, SQLITE_TRANSIENT); } - // Convert char* to string to trigger op<<(..., const std::string ) - template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char(&STR)[N]) { return bind_col_in_db(stmt, inx, std::string(STR, N-1)); } + // Convert char* to string_view to trigger op<<(..., const std::string_view ) + template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char(&STR)[N]) { return bind_col_in_db(stmt, inx, std::string_view(STR, N-1)); } inline std::string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) { return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::string() : @@ -170,30 +171,31 @@ namespace sqlite { std::string(reinterpret_cast(sqlite3_value_text(value)), sqlite3_value_bytes(value)); } - inline void store_result_in_db(sqlite3_context* db, const std::string& val) { + inline void store_result_in_db(sqlite3_context* db, const std::string_view& val) { sqlite3_result_text(db, val.data(), -1, SQLITE_TRANSIENT); } - // std::u16string + // std::u16string_view + template<> + struct has_sqlite_type : std::true_type {}; template<> struct has_sqlite_type : std::true_type {}; - - inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::u16string& val) { + inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::u16string_view& val) { return sqlite3_bind_text16(stmt, inx, val.data(), -1, SQLITE_TRANSIENT); } - // Convert char* to string to trigger op<<(..., const std::string ) - template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char16_t(&STR)[N]) { return bind_col_in_db(stmt, inx, std::u16string(STR, N-1)); } + // Convert char* to string_view to trigger op<<(..., const std::string_view ) + template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char16_t(&STR)[N]) { return bind_col_in_db(stmt, inx, std::u16string_view(STR, N-1)); } inline std::u16string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) { return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::u16string() : std::u16string(reinterpret_cast(sqlite3_column_text16(stmt, inx)), sqlite3_column_bytes16(stmt, inx)); } - inline std::u16string get_val_from_db(sqlite3_value *value, result_type) { + inline std::u16string get_val_from_db(sqlite3_value *value, result_type) { return sqlite3_value_type(value) == SQLITE_NULL ? std::u16string() : std::u16string(reinterpret_cast(sqlite3_value_text16(value)), sqlite3_value_bytes16(value)); } - inline void store_result_in_db(sqlite3_context* db, const std::u16string& val) { + inline void store_result_in_db(sqlite3_context* db, const std::u16string_view& val) { sqlite3_result_text16(db, val.data(), -1, SQLITE_TRANSIENT); } From c69ffc1cb0da74cb2d649e33452e57b3a09f1635 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 15 Jun 2018 15:34:57 -0600 Subject: [PATCH 05/21] Fallback to traditional string on pre-c++17 compilers --- hdr/sqlite_modern_cpp.h | 30 ++++++++++++++------------ hdr/sqlite_modern_cpp/errors.h | 8 +++---- hdr/sqlite_modern_cpp/type_wrapper.h | 32 +++++++++++++++++----------- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index 2ac6b6f7..736891c9 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -42,7 +42,7 @@ namespace sqlite { void execute(); - std::string_view sql() { + STR_REF sql() { #if SQLITE_VERSION_NUMBER >= 3014000 auto sqlite_deleter = [](void *ptr) {sqlite3_free(ptr);}; std::unique_ptr str(sqlite3_expanded_sql(_stmt.get()), sqlite_deleter); @@ -52,7 +52,7 @@ namespace sqlite { #endif } - std::string_view original_sql() { + STR_REF original_sql() { return sqlite3_sql(_stmt.get()); } @@ -85,7 +85,7 @@ namespace sqlite { return ++_inx; } - sqlite3_stmt* _prepare(const std::u16string_view& sql) { + sqlite3_stmt* _prepare(const U16STR_REF& sql) { //return _prepare(utility::utf16_to_utf8(sql)); int hresult; sqlite3_stmt* tmp = nullptr; @@ -97,7 +97,7 @@ namespace sqlite { return tmp; } - sqlite3_stmt* _prepare(const std::string_view& sql) { + sqlite3_stmt* _prepare(const STR_REF& sql) { int hresult; sqlite3_stmt* tmp = nullptr; const char *remaining; @@ -113,13 +113,13 @@ namespace sqlite { public: - database_binder(std::shared_ptr db, std::u16string_view const & sql): + database_binder(std::shared_ptr db, U16STR_REF const & sql): _db(db), _stmt(_prepare(sql), sqlite3_finalize), _inx(0) { } - database_binder(std::shared_ptr db, std::string_view const & sql): + database_binder(std::shared_ptr db, STR_REF const & sql): _db(db), _stmt(_prepare(sql), sqlite3_finalize), _inx(0) { @@ -370,7 +370,7 @@ namespace sqlite { std::shared_ptr _db; public: - database(const std::string_view &db_name, const sqlite_config &config = {}): _db(nullptr) { + database(const STR_REF &db_name, const sqlite_config &config = {}): _db(nullptr) { sqlite3* tmp = nullptr; auto ret = sqlite3_open_v2(db_name.data(), &tmp, static_cast(config.flags), config.zVfs); _db = std::shared_ptr(tmp, [=](sqlite3* ptr) { sqlite3_close_v2(ptr); }); // this will close the connection eventually when no longer needed. @@ -380,7 +380,7 @@ namespace sqlite { *this << R"(PRAGMA encoding = "UTF-16";)"; } - database(const std::u16string_view &db_name, const sqlite_config &config = {}): _db(nullptr) { + database(const U16STR_REF &db_name, const sqlite_config &config = {}): _db(nullptr) { auto db_name_utf8 = utility::utf16_to_utf8(db_name.data()); sqlite3* tmp = nullptr; auto ret = sqlite3_open_v2(db_name_utf8.data(), &tmp, static_cast(config.flags), config.zVfs); @@ -394,20 +394,20 @@ namespace sqlite { database(std::shared_ptr db): _db(db) {} - database_binder operator<<(const std::string_view& sql) { + database_binder operator<<(const STR_REF& sql) { return database_binder(_db, sql); } database_binder operator<<(const char* sql) { - return *this << std::string_view(sql); + return *this << STR_REF(sql); } - database_binder operator<<(const std::u16string_view& sql) { + database_binder operator<<(const U16STR_REF& sql) { return database_binder(_db, sql); } database_binder operator<<(const char16_t* sql) { - return *this << std::u16string_view(sql); + return *this << U16STR_REF(sql); } connection_type connection() const { return _db; } @@ -421,7 +421,7 @@ namespace sqlite { } template - void define(const std::string_view &name, Function&& func) { + void define(const STR_REF &name, Function&& func) { typedef utility::function_traits traits; auto funcPtr = new auto(std::forward(func)); @@ -435,7 +435,7 @@ namespace sqlite { } template - void define(const std::string_view &name, StepFunction&& step, FinalFunction&& final) { + void define(const STR_REF &name, StepFunction&& step, FinalFunction&& final) { typedef utility::function_traits traits; using ContextType = typename std::remove_reference>::type; @@ -660,3 +660,5 @@ namespace sqlite { } } } +#undef STR_REF +#undef U16STR_REF \ No newline at end of file diff --git a/hdr/sqlite_modern_cpp/errors.h b/hdr/sqlite_modern_cpp/errors.h index c22b5c0c..88117f8b 100644 --- a/hdr/sqlite_modern_cpp/errors.h +++ b/hdr/sqlite_modern_cpp/errors.h @@ -9,11 +9,11 @@ namespace sqlite { class sqlite_exception: public std::runtime_error { public: - sqlite_exception(const char* msg, std::string_view sql, int code = -1): runtime_error(msg), code(code), sql(sql) {} - sqlite_exception(int code, std::string_view sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {} + sqlite_exception(const char* msg, STR_REF sql, int code = -1): runtime_error(msg), code(code), sql(sql) {} + sqlite_exception(int code, STR_REF sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {} int get_code() const {return code & 0xFF;} int get_extended_code() const {return code;} - std::string_view get_sql() const {return sql;} + STR_REF get_sql() const {return sql;} private: int code; std::string sql; @@ -40,7 +40,7 @@ namespace sqlite { class more_statements: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements can only contain one statement class invalid_utf16: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - static void throw_sqlite_error(const int& error_code, const std::string_view &sql = "") { + static void throw_sqlite_error(const int& error_code, const STR_REF &sql = "") { switch(error_code & 0xFF) { #define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \ case SQLITE_ ## NAME: switch(error_code) { \ diff --git a/hdr/sqlite_modern_cpp/type_wrapper.h b/hdr/sqlite_modern_cpp/type_wrapper.h index 9ba7aeaa..3c4037e5 100644 --- a/hdr/sqlite_modern_cpp/type_wrapper.h +++ b/hdr/sqlite_modern_cpp/type_wrapper.h @@ -4,7 +4,13 @@ #include #include #include - +#ifdef __cplusplus >= 201703 && __has_include() +#define STR_REF std::string_view +#define U16STR_REF std::u16string_view +#else +#define STR_REF std::string +#define U16STR_REF std::u16string +#endif #ifdef __has_include #if __cplusplus > 201402 && __has_include() #define MODERN_SQLITE_STD_OPTIONAL_SUPPORT @@ -150,17 +156,17 @@ namespace sqlite { sqlite3_result_null(db); } - // std::string_view + // STR_REF template<> - struct has_sqlite_type : std::true_type {}; + struct has_sqlite_type : std::true_type {}; template<> struct has_sqlite_type : std::true_type {}; - inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::string_view& val) { + inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const STR_REF& val) { return sqlite3_bind_text(stmt, inx, val.data(), -1, SQLITE_TRANSIENT); } - // Convert char* to string_view to trigger op<<(..., const std::string_view ) - template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char(&STR)[N]) { return bind_col_in_db(stmt, inx, std::string_view(STR, N-1)); } + // Convert char* to string_view to trigger op<<(..., const STR_REF ) + template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char(&STR)[N]) { return bind_col_in_db(stmt, inx, STR_REF(STR, N-1)); } inline std::string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) { return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::string() : @@ -171,20 +177,20 @@ namespace sqlite { std::string(reinterpret_cast(sqlite3_value_text(value)), sqlite3_value_bytes(value)); } - inline void store_result_in_db(sqlite3_context* db, const std::string_view& val) { + inline void store_result_in_db(sqlite3_context* db, const STR_REF& val) { sqlite3_result_text(db, val.data(), -1, SQLITE_TRANSIENT); } - // std::u16string_view + // U16STR_REF template<> - struct has_sqlite_type : std::true_type {}; + struct has_sqlite_type : std::true_type {}; template<> struct has_sqlite_type : std::true_type {}; - inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const std::u16string_view& val) { + inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const U16STR_REF& val) { return sqlite3_bind_text16(stmt, inx, val.data(), -1, SQLITE_TRANSIENT); } - // Convert char* to string_view to trigger op<<(..., const std::string_view ) - template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char16_t(&STR)[N]) { return bind_col_in_db(stmt, inx, std::u16string_view(STR, N-1)); } + // Convert char* to string_view to trigger op<<(..., const STR_REF ) + template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char16_t(&STR)[N]) { return bind_col_in_db(stmt, inx, U16STR_REF(STR, N-1)); } inline std::u16string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) { return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::u16string() : @@ -195,7 +201,7 @@ namespace sqlite { std::u16string(reinterpret_cast(sqlite3_value_text16(value)), sqlite3_value_bytes16(value)); } - inline void store_result_in_db(sqlite3_context* db, const std::u16string_view& val) { + inline void store_result_in_db(sqlite3_context* db, const U16STR_REF& val) { sqlite3_result_text16(db, val.data(), -1, SQLITE_TRANSIENT); } From e0e3a221a0cebe9a7d04baf31589990226069c57 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 15 Jun 2018 15:52:03 -0600 Subject: [PATCH 06/21] Looks like String.h doesn't include string_view.h, maybe this will fix travis ci build? --- hdr/sqlite_modern_cpp/type_wrapper.h | 1 + 1 file changed, 1 insertion(+) diff --git a/hdr/sqlite_modern_cpp/type_wrapper.h b/hdr/sqlite_modern_cpp/type_wrapper.h index 3c4037e5..f4fb5f90 100644 --- a/hdr/sqlite_modern_cpp/type_wrapper.h +++ b/hdr/sqlite_modern_cpp/type_wrapper.h @@ -5,6 +5,7 @@ #include #include #ifdef __cplusplus >= 201703 && __has_include() +#include #define STR_REF std::string_view #define U16STR_REF std::u16string_view #else From 6c95d0a467a0a77cc7e3a1ee81abdf67f643c5cc Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 15 Jun 2018 16:07:14 -0600 Subject: [PATCH 07/21] Fix preprocessor directives --- hdr/sqlite_modern_cpp/type_wrapper.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hdr/sqlite_modern_cpp/type_wrapper.h b/hdr/sqlite_modern_cpp/type_wrapper.h index f4fb5f90..84c73644 100644 --- a/hdr/sqlite_modern_cpp/type_wrapper.h +++ b/hdr/sqlite_modern_cpp/type_wrapper.h @@ -4,7 +4,8 @@ #include #include #include -#ifdef __cplusplus >= 201703 && __has_include() +#ifdef __has_include +#if __cplusplus >= 201703 && __has_include() #include #define STR_REF std::string_view #define U16STR_REF std::u16string_view @@ -12,6 +13,10 @@ #define STR_REF std::string #define U16STR_REF std::u16string #endif +#else +#define STR_REF std::string +#define U16STR_REF std::u16string +#endif #ifdef __has_include #if __cplusplus > 201402 && __has_include() #define MODERN_SQLITE_STD_OPTIONAL_SUPPORT From 3b181fe2e264b0d4ae7d61eba1692e5c9afee485 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 15 Jun 2018 16:18:11 -0600 Subject: [PATCH 08/21] has_sqlite_type specifically for stringviews is unnecessary, it looks like --- hdr/sqlite_modern_cpp/type_wrapper.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hdr/sqlite_modern_cpp/type_wrapper.h b/hdr/sqlite_modern_cpp/type_wrapper.h index 84c73644..1c224734 100644 --- a/hdr/sqlite_modern_cpp/type_wrapper.h +++ b/hdr/sqlite_modern_cpp/type_wrapper.h @@ -6,6 +6,7 @@ #include #ifdef __has_include #if __cplusplus >= 201703 && __has_include() +#define MODERN_SQLITE_STRINGVIEW_SUPPORT #include #define STR_REF std::string_view #define U16STR_REF std::u16string_view @@ -164,8 +165,6 @@ namespace sqlite { // STR_REF template<> - struct has_sqlite_type : std::true_type {}; - template<> struct has_sqlite_type : std::true_type {}; inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const STR_REF& val) { return sqlite3_bind_text(stmt, inx, val.data(), -1, SQLITE_TRANSIENT); @@ -188,8 +187,6 @@ namespace sqlite { } // U16STR_REF template<> - struct has_sqlite_type : std::true_type {}; - template<> struct has_sqlite_type : std::true_type {}; inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const U16STR_REF& val) { return sqlite3_bind_text16(stmt, inx, val.data(), -1, SQLITE_TRANSIENT); From b9ddb6bac2b2c88958986cee9843881e788eb771 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sat, 16 Jun 2018 22:26:30 -0600 Subject: [PATCH 09/21] Original SQL should have string, not string_view return type. --- hdr/sqlite_modern_cpp.h | 4 ++-- hdr/sqlite_modern_cpp/errors.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index 736891c9..d02988b1 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -42,7 +42,7 @@ namespace sqlite { void execute(); - STR_REF sql() { + std::string sql() { #if SQLITE_VERSION_NUMBER >= 3014000 auto sqlite_deleter = [](void *ptr) {sqlite3_free(ptr);}; std::unique_ptr str(sqlite3_expanded_sql(_stmt.get()), sqlite_deleter); @@ -52,7 +52,7 @@ namespace sqlite { #endif } - STR_REF original_sql() { + std::string original_sql() { return sqlite3_sql(_stmt.get()); } diff --git a/hdr/sqlite_modern_cpp/errors.h b/hdr/sqlite_modern_cpp/errors.h index 88117f8b..f64153b9 100644 --- a/hdr/sqlite_modern_cpp/errors.h +++ b/hdr/sqlite_modern_cpp/errors.h @@ -9,11 +9,11 @@ namespace sqlite { class sqlite_exception: public std::runtime_error { public: - sqlite_exception(const char* msg, STR_REF sql, int code = -1): runtime_error(msg), code(code), sql(sql) {} - sqlite_exception(int code, STR_REF sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {} + sqlite_exception(const char* msg, STR_REF sql, int code = -1): runtime_error(msg), code(code), sql(std::move(sql)) {} + sqlite_exception(int code, STR_REF sql): runtime_error(sqlite3_errstr(code)), code(code), sql(std::move(sql)) {} int get_code() const {return code & 0xFF;} int get_extended_code() const {return code;} - STR_REF get_sql() const {return sql;} + std::string get_sql() const {return sql;} private: int code; std::string sql; From b08f6b64036d1ea85d4ce83e9fef1641d943d2db Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 17 Jun 2018 10:06:00 -0600 Subject: [PATCH 10/21] Reuse UTF-8 prepare function, and add length to prepare call --- hdr/sqlite_modern_cpp.h | 12 ++---------- hdr/sqlite_modern_cpp/utility/utf16_utf8.h | 2 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index d02988b1..4542cf72 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -86,22 +86,14 @@ namespace sqlite { } sqlite3_stmt* _prepare(const U16STR_REF& sql) { - //return _prepare(utility::utf16_to_utf8(sql)); - int hresult; - sqlite3_stmt* tmp = nullptr; - const void *remaining; - hresult = sqlite3_prepare16_v2(_db.get(), sql.data(), -1, &tmp, &remaining); - if (hresult != SQLITE_OK) errors::throw_sqlite_error(hresult, utility::utf16_to_utf8(sql.data())); - if (!std::all_of(static_cast(remaining), sql.data() + sql.size(), [](char16_t ch) {return std::isspace(ch); })) - throw errors::more_statements("Multiple semicolon separated statements are unsupported", utility::utf16_to_utf8(sql.data())); - return tmp; + return _prepare(utility::utf16_to_utf8(sql)); } sqlite3_stmt* _prepare(const STR_REF& sql) { int hresult; sqlite3_stmt* tmp = nullptr; const char *remaining; - hresult = sqlite3_prepare_v2(_db.get(), sql.data(), -1, &tmp, &remaining); + hresult = sqlite3_prepare_v2(_db.get(), sql.data(), sql.length(), &tmp, &remaining); if(hresult != SQLITE_OK) errors::throw_sqlite_error(hresult, sql); if(!std::all_of(remaining, sql.data() + sql.size(), [](char ch) {return std::isspace(ch);})) throw errors::more_statements("Multiple semicolon separated statements are unsupported", sql); diff --git a/hdr/sqlite_modern_cpp/utility/utf16_utf8.h b/hdr/sqlite_modern_cpp/utility/utf16_utf8.h index ea21723f..b54c340b 100644 --- a/hdr/sqlite_modern_cpp/utility/utf16_utf8.h +++ b/hdr/sqlite_modern_cpp/utility/utf16_utf8.h @@ -8,7 +8,7 @@ namespace sqlite { namespace utility { - inline std::string utf16_to_utf8(const std::u16string &input) { + inline std::string utf16_to_utf8(const U16STR_REF &input) { struct : std::codecvt { } codecvt; std::mbstate_t state{}; From 080411aeae2d8471f3c486bc648197cf66fbea82 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 17 Jun 2018 10:27:35 -0600 Subject: [PATCH 11/21] Switch back to string parameters for database constructor Also got rid of some redundant code --- hdr/sqlite_modern_cpp.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index 4542cf72..e6515522 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -362,7 +362,7 @@ namespace sqlite { std::shared_ptr _db; public: - database(const STR_REF &db_name, const sqlite_config &config = {}): _db(nullptr) { + database(const std::string &db_name, const sqlite_config &config = {}): _db(nullptr) { sqlite3* tmp = nullptr; auto ret = sqlite3_open_v2(db_name.data(), &tmp, static_cast(config.flags), config.zVfs); _db = std::shared_ptr(tmp, [=](sqlite3* ptr) { sqlite3_close_v2(ptr); }); // this will close the connection eventually when no longer needed. @@ -372,14 +372,8 @@ namespace sqlite { *this << R"(PRAGMA encoding = "UTF-16";)"; } - database(const U16STR_REF &db_name, const sqlite_config &config = {}): _db(nullptr) { - auto db_name_utf8 = utility::utf16_to_utf8(db_name.data()); - sqlite3* tmp = nullptr; - auto ret = sqlite3_open_v2(db_name_utf8.data(), &tmp, static_cast(config.flags), config.zVfs); - _db = std::shared_ptr(tmp, [=](sqlite3* ptr) { sqlite3_close_v2(ptr); }); // this will close the connection eventually when no longer needed. - if(ret != SQLITE_OK) errors::throw_sqlite_error(_db ? sqlite3_extended_errcode(_db.get()) : ret); - sqlite3_extended_result_codes(_db.get(), true); - if(config.encoding != Encoding::UTF8) + database(const std::u16string &db_name, const sqlite_config &config = {}): database(utility::utf16_to_utf8(db_name.data()), config) { + if (config.encoding == Encoding::ANY) *this << R"(PRAGMA encoding = "UTF-16";)"; } From 64f5f662d2ed096736b1ebd1348d400560355b01 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 17 Jun 2018 10:35:08 -0600 Subject: [PATCH 12/21] Function definitions back to std::string --- hdr/sqlite_modern_cpp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index e6515522..189a43ee 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -407,7 +407,7 @@ namespace sqlite { } template - void define(const STR_REF &name, Function&& func) { + void define(const std::string &name, Function&& func) { typedef utility::function_traits traits; auto funcPtr = new auto(std::forward(func)); @@ -421,7 +421,7 @@ namespace sqlite { } template - void define(const STR_REF &name, StepFunction&& step, FinalFunction&& final) { + void define(const std::string &name, StepFunction&& step, FinalFunction&& final) { typedef utility::function_traits traits; using ContextType = typename std::remove_reference>::type; From 9e567360e999fe2439e98e79dd0c6a62e2be414a Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 17 Jun 2018 10:55:55 -0600 Subject: [PATCH 13/21] Sizes for string_view functions --- hdr/sqlite_modern_cpp/type_wrapper.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hdr/sqlite_modern_cpp/type_wrapper.h b/hdr/sqlite_modern_cpp/type_wrapper.h index 1c224734..117de325 100644 --- a/hdr/sqlite_modern_cpp/type_wrapper.h +++ b/hdr/sqlite_modern_cpp/type_wrapper.h @@ -167,7 +167,7 @@ namespace sqlite { template<> struct has_sqlite_type : std::true_type {}; inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const STR_REF& val) { - return sqlite3_bind_text(stmt, inx, val.data(), -1, SQLITE_TRANSIENT); + return sqlite3_bind_text(stmt, inx, val.data(), val.length(), SQLITE_TRANSIENT); } // Convert char* to string_view to trigger op<<(..., const STR_REF ) @@ -183,13 +183,13 @@ namespace sqlite { } inline void store_result_in_db(sqlite3_context* db, const STR_REF& val) { - sqlite3_result_text(db, val.data(), -1, SQLITE_TRANSIENT); + sqlite3_result_text(db, val.data(), val.length(), SQLITE_TRANSIENT); } // U16STR_REF template<> struct has_sqlite_type : std::true_type {}; inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const U16STR_REF& val) { - return sqlite3_bind_text16(stmt, inx, val.data(), -1, SQLITE_TRANSIENT); + return sqlite3_bind_text16(stmt, inx, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT); } // Convert char* to string_view to trigger op<<(..., const STR_REF ) @@ -205,7 +205,7 @@ namespace sqlite { } inline void store_result_in_db(sqlite3_context* db, const U16STR_REF& val) { - sqlite3_result_text16(db, val.data(), -1, SQLITE_TRANSIENT); + sqlite3_result_text16(db, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT); } // Other integer types From a1849e2015c70f97d69ae903d2dfdfb43dedb0de Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 17 Jun 2018 11:03:17 -0600 Subject: [PATCH 14/21] Change preprocessor options for string_view to be more consistent with other options Also makes it so people can manually define MODERN_SQLITE_STRINGVIEW_SUPPORT if they want --- hdr/sqlite_modern_cpp/type_wrapper.h | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/hdr/sqlite_modern_cpp/type_wrapper.h b/hdr/sqlite_modern_cpp/type_wrapper.h index 117de325..2688f525 100644 --- a/hdr/sqlite_modern_cpp/type_wrapper.h +++ b/hdr/sqlite_modern_cpp/type_wrapper.h @@ -7,16 +7,7 @@ #ifdef __has_include #if __cplusplus >= 201703 && __has_include() #define MODERN_SQLITE_STRINGVIEW_SUPPORT -#include -#define STR_REF std::string_view -#define U16STR_REF std::u16string_view -#else -#define STR_REF std::string -#define U16STR_REF std::u16string #endif -#else -#define STR_REF std::string -#define U16STR_REF std::u16string #endif #ifdef __has_include #if __cplusplus > 201402 && __has_include() @@ -44,7 +35,14 @@ #ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT #include #endif - +#ifdef MODERN_SQLITE_STRINGVIEW_SUPPORT +#include +#define STR_REF std::string_view +#define U16STR_REF std::u16string_view +#else +#define STR_REF std::string +#define U16STR_REF std::u16string +#endif #include #include "errors.h" From fac3344414290c4f1ba4fd6bf423061dafa441e4 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 17 Jun 2018 16:01:03 -0600 Subject: [PATCH 15/21] Switch to typedef instead of define --- hdr/sqlite_modern_cpp/type_wrapper.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hdr/sqlite_modern_cpp/type_wrapper.h b/hdr/sqlite_modern_cpp/type_wrapper.h index 2688f525..0afa64f5 100644 --- a/hdr/sqlite_modern_cpp/type_wrapper.h +++ b/hdr/sqlite_modern_cpp/type_wrapper.h @@ -37,11 +37,11 @@ #endif #ifdef MODERN_SQLITE_STRINGVIEW_SUPPORT #include -#define STR_REF std::string_view -#define U16STR_REF std::u16string_view +typedef std::string_view STR_REF; +typedef std::u16string_view U16STR_REF; #else -#define STR_REF std::string -#define U16STR_REF std::u16string +typedef std::string STR_REF; +typedef std::u16string U16STR_REF; #endif #include #include "errors.h" From 8e09803f4ad5a5ee95c7bb991282e781427d6bc6 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 17 Jun 2018 16:26:07 -0600 Subject: [PATCH 16/21] Pass string_view by value --- hdr/sqlite_modern_cpp.h | 23 +++++++---------------- hdr/sqlite_modern_cpp/type_wrapper.h | 24 ++++++++++++++---------- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index 189a43ee..16491b65 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -85,11 +85,11 @@ namespace sqlite { return ++_inx; } - sqlite3_stmt* _prepare(const U16STR_REF& sql) { + sqlite3_stmt* _prepare(U16STR_REF sql) { return _prepare(utility::utf16_to_utf8(sql)); } - sqlite3_stmt* _prepare(const STR_REF& sql) { + sqlite3_stmt* _prepare(STR_REF sql) { int hresult; sqlite3_stmt* tmp = nullptr; const char *remaining; @@ -105,13 +105,13 @@ namespace sqlite { public: - database_binder(std::shared_ptr db, U16STR_REF const & sql): + database_binder(std::shared_ptr db, U16STR_REF sql): _db(db), _stmt(_prepare(sql), sqlite3_finalize), _inx(0) { } - database_binder(std::shared_ptr db, STR_REF const & sql): + database_binder(std::shared_ptr db, STR_REF sql): _db(db), _stmt(_prepare(sql), sqlite3_finalize), _inx(0) { @@ -380,22 +380,14 @@ namespace sqlite { database(std::shared_ptr db): _db(db) {} - database_binder operator<<(const STR_REF& sql) { + database_binder operator<<(STR_REF sql) { return database_binder(_db, sql); } - database_binder operator<<(const char* sql) { - return *this << STR_REF(sql); - } - - database_binder operator<<(const U16STR_REF& sql) { + database_binder operator<<(U16STR_REF sql) { return database_binder(_db, sql); } - database_binder operator<<(const char16_t* sql) { - return *this << U16STR_REF(sql); - } - connection_type connection() const { return _db; } sqlite3_int64 last_insert_rowid() const { @@ -646,5 +638,4 @@ namespace sqlite { } } } -#undef STR_REF -#undef U16STR_REF \ No newline at end of file + diff --git a/hdr/sqlite_modern_cpp/type_wrapper.h b/hdr/sqlite_modern_cpp/type_wrapper.h index 0afa64f5..e94a5226 100644 --- a/hdr/sqlite_modern_cpp/type_wrapper.h +++ b/hdr/sqlite_modern_cpp/type_wrapper.h @@ -37,11 +37,11 @@ #endif #ifdef MODERN_SQLITE_STRINGVIEW_SUPPORT #include -typedef std::string_view STR_REF; -typedef std::u16string_view U16STR_REF; +typedef const std::string_view STR_REF; +typedef const std::u16string_view U16STR_REF; #else -typedef std::string STR_REF; -typedef std::u16string U16STR_REF; +typedef const std::string& STR_REF; +typedef const std::u16string& U16STR_REF; #endif #include #include "errors.h" @@ -164,12 +164,14 @@ namespace sqlite { // STR_REF template<> struct has_sqlite_type : std::true_type {}; - inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const STR_REF& val) { + inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, STR_REF val) { return sqlite3_bind_text(stmt, inx, val.data(), val.length(), SQLITE_TRANSIENT); } // Convert char* to string_view to trigger op<<(..., const STR_REF ) - template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char(&STR)[N]) { return bind_col_in_db(stmt, inx, STR_REF(STR, N-1)); } + template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char(&STR)[N]) { + return sqlite3_bind_text(stmt, inx, &STR[0], N-1, SQLITE_TRANSIENT); + } inline std::string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) { return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::string() : @@ -180,18 +182,20 @@ namespace sqlite { std::string(reinterpret_cast(sqlite3_value_text(value)), sqlite3_value_bytes(value)); } - inline void store_result_in_db(sqlite3_context* db, const STR_REF& val) { + inline void store_result_in_db(sqlite3_context* db, STR_REF val) { sqlite3_result_text(db, val.data(), val.length(), SQLITE_TRANSIENT); } // U16STR_REF template<> struct has_sqlite_type : std::true_type {}; - inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const U16STR_REF& val) { + inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, U16STR_REF val) { return sqlite3_bind_text16(stmt, inx, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT); } // Convert char* to string_view to trigger op<<(..., const STR_REF ) - template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char16_t(&STR)[N]) { return bind_col_in_db(stmt, inx, U16STR_REF(STR, N-1)); } + template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char16_t(&STR)[N]) { + return sqlite3_bind_text16(stmt, inx, &STR[0], N-1, SQLITE_TRANSIENT); + } inline std::u16string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) { return sqlite3_column_type(stmt, inx) == SQLITE_NULL ? std::u16string() : @@ -202,7 +206,7 @@ namespace sqlite { std::u16string(reinterpret_cast(sqlite3_value_text16(value)), sqlite3_value_bytes16(value)); } - inline void store_result_in_db(sqlite3_context* db, const U16STR_REF& val) { + inline void store_result_in_db(sqlite3_context* db, U16STR_REF val) { sqlite3_result_text16(db, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT); } From 7d6ea221735ecb47d141446aee67bfc256eef563 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 18 Jun 2018 09:41:36 -0600 Subject: [PATCH 17/21] Small Changes --- hdr/sqlite_modern_cpp.h | 16 ++++++------ hdr/sqlite_modern_cpp/errors.h | 6 ++--- hdr/sqlite_modern_cpp/type_wrapper.h | 30 +++++++++++++--------- hdr/sqlite_modern_cpp/utility/utf16_utf8.h | 2 +- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index 16491b65..a19c9851 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -85,11 +85,11 @@ namespace sqlite { return ++_inx; } - sqlite3_stmt* _prepare(U16STR_REF sql) { + sqlite3_stmt* _prepare(u16str_ref sql) { return _prepare(utility::utf16_to_utf8(sql)); } - sqlite3_stmt* _prepare(STR_REF sql) { + sqlite3_stmt* _prepare(str_ref sql) { int hresult; sqlite3_stmt* tmp = nullptr; const char *remaining; @@ -105,13 +105,13 @@ namespace sqlite { public: - database_binder(std::shared_ptr db, U16STR_REF sql): + database_binder(std::shared_ptr db, u16str_ref sql): _db(db), _stmt(_prepare(sql), sqlite3_finalize), _inx(0) { } - database_binder(std::shared_ptr db, STR_REF sql): + database_binder(std::shared_ptr db, str_ref sql): _db(db), _stmt(_prepare(sql), sqlite3_finalize), _inx(0) { @@ -372,7 +372,7 @@ namespace sqlite { *this << R"(PRAGMA encoding = "UTF-16";)"; } - database(const std::u16string &db_name, const sqlite_config &config = {}): database(utility::utf16_to_utf8(db_name.data()), config) { + database(const std::u16string &db_name, const sqlite_config &config = {}): database(utility::utf16_to_utf8(db_name), config) { if (config.encoding == Encoding::ANY) *this << R"(PRAGMA encoding = "UTF-16";)"; } @@ -380,11 +380,11 @@ namespace sqlite { database(std::shared_ptr db): _db(db) {} - database_binder operator<<(STR_REF sql) { + database_binder operator<<(str_ref sql) { return database_binder(_db, sql); } - database_binder operator<<(U16STR_REF sql) { + database_binder operator<<(u16str_ref sql) { return database_binder(_db, sql); } @@ -419,7 +419,7 @@ namespace sqlite { auto funcPtr = new auto(std::make_pair(std::forward(step), std::forward(final))); if(int result = sqlite3_create_function_v2( - _db.get(), name.data(), traits::arity - 1, SQLITE_UTF8, funcPtr, nullptr, + _db.get(), name.c_str(), traits::arity - 1, SQLITE_UTF8, funcPtr, nullptr, sql_function_binder::step::type>, sql_function_binder::final::type>, [](void* ptr){ diff --git a/hdr/sqlite_modern_cpp/errors.h b/hdr/sqlite_modern_cpp/errors.h index f64153b9..07d12e00 100644 --- a/hdr/sqlite_modern_cpp/errors.h +++ b/hdr/sqlite_modern_cpp/errors.h @@ -9,8 +9,8 @@ namespace sqlite { class sqlite_exception: public std::runtime_error { public: - sqlite_exception(const char* msg, STR_REF sql, int code = -1): runtime_error(msg), code(code), sql(std::move(sql)) {} - sqlite_exception(int code, STR_REF sql): runtime_error(sqlite3_errstr(code)), code(code), sql(std::move(sql)) {} + sqlite_exception(const char* msg, str_ref sql, int code = -1): runtime_error(msg), code(code), sql(sql) {} + sqlite_exception(int code, str_ref sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {} int get_code() const {return code & 0xFF;} int get_extended_code() const {return code;} std::string get_sql() const {return sql;} @@ -40,7 +40,7 @@ namespace sqlite { class more_statements: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements can only contain one statement class invalid_utf16: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - static void throw_sqlite_error(const int& error_code, const STR_REF &sql = "") { + static void throw_sqlite_error(const int& error_code, str_ref sql = "") { switch(error_code & 0xFF) { #define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \ case SQLITE_ ## NAME: switch(error_code) { \ diff --git a/hdr/sqlite_modern_cpp/type_wrapper.h b/hdr/sqlite_modern_cpp/type_wrapper.h index e94a5226..1634a11d 100644 --- a/hdr/sqlite_modern_cpp/type_wrapper.h +++ b/hdr/sqlite_modern_cpp/type_wrapper.h @@ -37,11 +37,17 @@ #endif #ifdef MODERN_SQLITE_STRINGVIEW_SUPPORT #include -typedef const std::string_view STR_REF; -typedef const std::u16string_view U16STR_REF; +namespace sqlite +{ + typedef const std::string_view str_ref; + typedef const std::u16string_view u16str_ref; +} #else -typedef const std::string& STR_REF; -typedef const std::u16string& U16STR_REF; +namespace sqlite +{ + typedef const std::string& sqlite::str_ref; + typedef const std::u16string& sqlite::u16str_ref; +} #endif #include #include "errors.h" @@ -161,14 +167,14 @@ namespace sqlite { sqlite3_result_null(db); } - // STR_REF + // str_ref template<> struct has_sqlite_type : std::true_type {}; - inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, STR_REF val) { + inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, str_ref val) { return sqlite3_bind_text(stmt, inx, val.data(), val.length(), SQLITE_TRANSIENT); } - // Convert char* to string_view to trigger op<<(..., const STR_REF ) + // Convert char* to string_view to trigger op<<(..., const str_ref ) template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char(&STR)[N]) { return sqlite3_bind_text(stmt, inx, &STR[0], N-1, SQLITE_TRANSIENT); } @@ -182,17 +188,17 @@ namespace sqlite { std::string(reinterpret_cast(sqlite3_value_text(value)), sqlite3_value_bytes(value)); } - inline void store_result_in_db(sqlite3_context* db, STR_REF val) { + inline void store_result_in_db(sqlite3_context* db, str_ref val) { sqlite3_result_text(db, val.data(), val.length(), SQLITE_TRANSIENT); } - // U16STR_REF + // u16str_ref template<> struct has_sqlite_type : std::true_type {}; - inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, U16STR_REF val) { + inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, u16str_ref val) { return sqlite3_bind_text16(stmt, inx, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT); } - // Convert char* to string_view to trigger op<<(..., const STR_REF ) + // Convert char* to string_view to trigger op<<(..., const str_ref ) template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char16_t(&STR)[N]) { return sqlite3_bind_text16(stmt, inx, &STR[0], N-1, SQLITE_TRANSIENT); } @@ -206,7 +212,7 @@ namespace sqlite { std::u16string(reinterpret_cast(sqlite3_value_text16(value)), sqlite3_value_bytes16(value)); } - inline void store_result_in_db(sqlite3_context* db, U16STR_REF val) { + inline void store_result_in_db(sqlite3_context* db, u16str_ref val) { sqlite3_result_text16(db, val.data(), sizeof(char16_t) * val.length(), SQLITE_TRANSIENT); } diff --git a/hdr/sqlite_modern_cpp/utility/utf16_utf8.h b/hdr/sqlite_modern_cpp/utility/utf16_utf8.h index b54c340b..6903cd9d 100644 --- a/hdr/sqlite_modern_cpp/utility/utf16_utf8.h +++ b/hdr/sqlite_modern_cpp/utility/utf16_utf8.h @@ -8,7 +8,7 @@ namespace sqlite { namespace utility { - inline std::string utf16_to_utf8(const U16STR_REF &input) { + inline std::string utf16_to_utf8(u16str_ref input) { struct : std::codecvt { } codecvt; std::mbstate_t state{}; From c03e4e8293d050fa52898ad475a1f455a4ab3147 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 18 Jun 2018 10:20:02 -0600 Subject: [PATCH 18/21] Add tests from string_view --- tests/string_view.cc | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/string_view.cc diff --git a/tests/string_view.cc b/tests/string_view.cc new file mode 100644 index 00000000..ecd8d251 --- /dev/null +++ b/tests/string_view.cc @@ -0,0 +1,26 @@ +#include +#include +#include +#include + + +#ifdef MODERN_SQLITE_STRINGVIEW_SUPPORT +#include + +using namespace sqlite; +using namespace std; +TEST_CASE("std::string_view works", "[string_view]") { + database db(":memory:");; + db << "CREATE TABLE foo (a integer, b string);\n"; + const std::string_view test1 = "null terminated string view"; + db << "INSERT INTO foo VALUES (?, ?)" << 1 << test1; + std::string str; + db << "SELECT b from FOO where a=?;" << 1 >> str; + REQUIRE(test1 == str); + const char s[] = "hello world"; + std::string_view test2(&s[0], 2); + db << "INSERT INTO foo VALUES (?,?)" << 2 << test2; + db << "SELECT b from FOO where a=?" << 2 >> str; + REQUIRE(str == "he"); +} +#endif \ No newline at end of file From b12f94950fe08f89214b2537f9dba92ecc852a5f Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 18 Jun 2018 11:05:57 -0600 Subject: [PATCH 19/21] Update Readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4d85af2f..95e938db 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ int main() { // int ,long, long long, float, double // string , u16string // sqlite3 only supports utf8 and utf16 strings, you should use std::string for utf8 and std::u16string for utf16. + // If you're using c++17, it takes `string_view` and `u16string_view` as arguments // note that u"my text" is a utf16 string literal of type char16_t * . db << "insert into user (age,name,weight) values (?,?,?);" << 20 From dffc09036c138fb6d5e5f9e85ca14816882dad11 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 18 Jun 2018 11:12:05 -0600 Subject: [PATCH 20/21] oops --- hdr/sqlite_modern_cpp/type_wrapper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hdr/sqlite_modern_cpp/type_wrapper.h b/hdr/sqlite_modern_cpp/type_wrapper.h index 1634a11d..ba27fea0 100644 --- a/hdr/sqlite_modern_cpp/type_wrapper.h +++ b/hdr/sqlite_modern_cpp/type_wrapper.h @@ -45,8 +45,8 @@ namespace sqlite #else namespace sqlite { - typedef const std::string& sqlite::str_ref; - typedef const std::u16string& sqlite::u16str_ref; + typedef const std::string& str_ref; + typedef const std::u16string& u16str_ref; } #endif #include From b0e3c8d27f635ba7ce9eb53504da6027ed126cd7 Mon Sep 17 00:00:00 2001 From: Jimmy Xiao Date: Mon, 18 Jun 2018 12:06:06 -0600 Subject: [PATCH 21/21] Sqlite takes bind text16 sizes in bytes --- hdr/sqlite_modern_cpp/type_wrapper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hdr/sqlite_modern_cpp/type_wrapper.h b/hdr/sqlite_modern_cpp/type_wrapper.h index ba27fea0..e17932fe 100644 --- a/hdr/sqlite_modern_cpp/type_wrapper.h +++ b/hdr/sqlite_modern_cpp/type_wrapper.h @@ -200,7 +200,7 @@ namespace sqlite { // Convert char* to string_view to trigger op<<(..., const str_ref ) template inline int bind_col_in_db(sqlite3_stmt* stmt, int inx, const char16_t(&STR)[N]) { - return sqlite3_bind_text16(stmt, inx, &STR[0], N-1, SQLITE_TRANSIENT); + return sqlite3_bind_text16(stmt, inx, &STR[0], sizeof(char16_t) * (N-1), SQLITE_TRANSIENT); } inline std::u16string get_col_from_db(sqlite3_stmt* stmt, int inx, result_type) {