From 2e683a4b695895a92eb55995148a3dad6051d191 Mon Sep 17 00:00:00 2001 From: Roland Bock Date: Sun, 1 Aug 2021 20:37:36 +0200 Subject: [PATCH] Moved sqlite3 over here. --- CMakeLists.txt | 39 +- include/sqlpp11/sqlite3/bind_result.h | 109 ++++ include/sqlpp11/sqlite3/connection.h | 359 ++++++++++++++ include/sqlpp11/sqlite3/connection_config.h | 71 +++ include/sqlpp11/sqlite3/dynamic_libsqlite3.h | 237 +++++++++ include/sqlpp11/sqlite3/export.h | 18 + include/sqlpp11/sqlite3/insert_or.h | 154 ++++++ include/sqlpp11/sqlite3/prepared_statement.h | 88 ++++ include/sqlpp11/sqlite3/serializer.h | 140 ++++++ include/sqlpp11/sqlite3/sqlite3.h | 33 ++ src/CMakeLists.txt | 35 ++ src/sqlite3/CMakeLists.txt | 96 ++++ src/sqlite3/bind_result.cpp | 249 ++++++++++ src/sqlite3/connection.cpp | 280 +++++++++++ src/sqlite3/detail/connection_handle.cpp | 85 ++++ src/sqlite3/detail/connection_handle.h | 61 +++ src/sqlite3/detail/dynamic_libsqlite3.cpp | 466 ++++++++++++++++++ .../detail/prepared_statement_handle.h | 96 ++++ src/sqlite3/prepared_statement.cpp | 245 +++++++++ tests/CMakeLists.txt | 70 +-- tests/core/CMakeLists.txt | 29 ++ .../core/constraints}/CMakeLists.txt | 0 .../core/constraints}/count_of_count.cpp | 0 .../core/constraints}/max_of_max.cpp | 0 .../core/constraints}/must_not_insert.cpp | 0 .../core/constraints}/must_not_update.cpp | 0 .../core/constraints}/require_insert.cpp | 0 .../core/serialize}/As.cpp | 0 .../core/serialize}/Blob.cpp | 0 .../core/serialize}/CMakeLists.txt | 0 .../core/serialize}/CustomQuery.cpp | 0 .../core/serialize}/DynamicWhere.cpp | 0 .../core/serialize}/ForUpdate.cpp | 0 .../core/serialize}/From.cpp | 0 .../core/serialize}/In.cpp | 0 .../core/serialize}/Insert.cpp | 0 .../core/serialize}/Over.cpp | 0 .../core/serialize}/ParameterizedVerbatim.cpp | 0 .../core/serialize}/TableAlias.cpp | 0 .../core/serialize}/Where.cpp | 0 .../core/serialize}/compare.h | 0 .../core/static_asserts}/AssertTables.h | 0 .../core/static_asserts}/AssertTables.sql | 0 .../core/static_asserts}/CMakeLists.txt | 0 .../core/static_asserts}/aggregates.cpp | 0 .../core/static_asserts}/case.cpp | 0 .../core/static_asserts}/date.cpp | 0 .../core/static_asserts}/date_time.cpp | 0 .../core/static_asserts}/from.cpp | 0 .../core/static_asserts}/having.cpp | 0 .../core/static_asserts}/in.cpp | 0 .../core/static_asserts}/insert.cpp | 0 .../core/static_asserts}/join.cpp | 0 .../core/static_asserts}/no_self_compare.cpp | 0 .../core/static_asserts}/text.cpp | 0 .../core/static_asserts}/unwrapped_bool.cpp | 0 .../core/static_asserts}/update_list.cpp | 0 .../core/static_asserts}/where.cpp | 0 tests/{ => core/usage}/BooleanExpression.cpp | 0 tests/core/usage/CMakeLists.txt | 79 +++ tests/{ => core/usage}/CustomQuery.cpp | 0 tests/{ => core/usage}/DateTime.cpp | 0 tests/{ => core/usage}/Function.cpp | 0 tests/{ => core/usage}/Insert.cpp | 0 tests/{ => core/usage}/Interpret.cpp | 0 tests/{ => core/usage}/Minimalistic.cpp | 0 tests/{ => core/usage}/MockDb.h | 0 tests/{ => core/usage}/Ppgen.cpp | 0 tests/{ => core/usage}/Prepared.cpp | 0 tests/{ => core/usage}/Remove.cpp | 0 tests/{ => core/usage}/Result.cpp | 0 tests/{ => core/usage}/Sample.h | 0 tests/{ => core/usage}/Select.cpp | 0 tests/{ => core/usage}/SelectType.cpp | 0 tests/{ => core/usage}/Union.cpp | 0 tests/{ => core/usage}/Update.cpp | 0 tests/{ => core/usage}/With.cpp | 0 tests/{ => core/usage}/is_regular.h | 0 tests/{ => core/usage}/sample.sql | 0 tests/sqlite3/CMakeLists.txt | 26 + tests/sqlite3/usage/AttachTest.cpp | 75 +++ tests/sqlite3/usage/AutoIncrementTest.cpp | 69 +++ tests/sqlite3/usage/BlobSample.h | 78 +++ tests/sqlite3/usage/BlobSample.sql | 4 + tests/sqlite3/usage/BlobTest.cpp | 102 ++++ tests/sqlite3/usage/CMakeLists.txt | 60 +++ tests/sqlite3/usage/DateTimeTest.cpp | 130 +++++ tests/sqlite3/usage/DynamicLoadingTest.cpp | 88 ++++ tests/sqlite3/usage/DynamicSelectTest.cpp | 86 ++++ tests/sqlite3/usage/FloatingPointTest.cpp | 126 +++++ tests/sqlite3/usage/FpSample.h | 79 +++ tests/sqlite3/usage/FpSample.sql | 4 + tests/sqlite3/usage/IntegralSample.h | 79 +++ tests/sqlite3/usage/IntegralTest.cpp | 119 +++++ tests/sqlite3/usage/SampleTest.cpp | 210 ++++++++ tests/sqlite3/usage/SelectTest.cpp | 173 +++++++ tests/sqlite3/usage/TabSample.h | 250 ++++++++++ tests/sqlite3/usage/TabSample.sql | 5 + tests/sqlite3/usage/TransactionTest.cpp | 84 ++++ tests/sqlite3/usage/UnionTest.cpp | 67 +++ tests/sqlite3/usage/WithTest.cpp | 71 +++ 101 files changed, 4963 insertions(+), 61 deletions(-) create mode 100644 include/sqlpp11/sqlite3/bind_result.h create mode 100644 include/sqlpp11/sqlite3/connection.h create mode 100644 include/sqlpp11/sqlite3/connection_config.h create mode 100644 include/sqlpp11/sqlite3/dynamic_libsqlite3.h create mode 100644 include/sqlpp11/sqlite3/export.h create mode 100644 include/sqlpp11/sqlite3/insert_or.h create mode 100644 include/sqlpp11/sqlite3/prepared_statement.h create mode 100644 include/sqlpp11/sqlite3/serializer.h create mode 100644 include/sqlpp11/sqlite3/sqlite3.h create mode 100644 src/CMakeLists.txt create mode 100644 src/sqlite3/CMakeLists.txt create mode 100644 src/sqlite3/bind_result.cpp create mode 100644 src/sqlite3/connection.cpp create mode 100644 src/sqlite3/detail/connection_handle.cpp create mode 100644 src/sqlite3/detail/connection_handle.h create mode 100644 src/sqlite3/detail/dynamic_libsqlite3.cpp create mode 100644 src/sqlite3/detail/prepared_statement_handle.h create mode 100644 src/sqlite3/prepared_statement.cpp create mode 100644 tests/core/CMakeLists.txt rename {test_constraints => tests/core/constraints}/CMakeLists.txt (100%) rename {test_constraints => tests/core/constraints}/count_of_count.cpp (100%) rename {test_constraints => tests/core/constraints}/max_of_max.cpp (100%) rename {test_constraints => tests/core/constraints}/must_not_insert.cpp (100%) rename {test_constraints => tests/core/constraints}/must_not_update.cpp (100%) rename {test_constraints => tests/core/constraints}/require_insert.cpp (100%) rename {test_serializer => tests/core/serialize}/As.cpp (100%) rename {test_serializer => tests/core/serialize}/Blob.cpp (100%) rename {test_serializer => tests/core/serialize}/CMakeLists.txt (100%) rename {test_serializer => tests/core/serialize}/CustomQuery.cpp (100%) rename {test_serializer => tests/core/serialize}/DynamicWhere.cpp (100%) rename {test_serializer => tests/core/serialize}/ForUpdate.cpp (100%) rename {test_serializer => tests/core/serialize}/From.cpp (100%) rename {test_serializer => tests/core/serialize}/In.cpp (100%) rename {test_serializer => tests/core/serialize}/Insert.cpp (100%) rename {test_serializer => tests/core/serialize}/Over.cpp (100%) rename {test_serializer => tests/core/serialize}/ParameterizedVerbatim.cpp (100%) rename {test_serializer => tests/core/serialize}/TableAlias.cpp (100%) rename {test_serializer => tests/core/serialize}/Where.cpp (100%) rename {test_serializer => tests/core/serialize}/compare.h (100%) rename {test_static_asserts => tests/core/static_asserts}/AssertTables.h (100%) rename {test_static_asserts => tests/core/static_asserts}/AssertTables.sql (100%) rename {test_static_asserts => tests/core/static_asserts}/CMakeLists.txt (100%) rename {test_static_asserts => tests/core/static_asserts}/aggregates.cpp (100%) rename {test_static_asserts => tests/core/static_asserts}/case.cpp (100%) rename {test_static_asserts => tests/core/static_asserts}/date.cpp (100%) rename {test_static_asserts => tests/core/static_asserts}/date_time.cpp (100%) rename {test_static_asserts => tests/core/static_asserts}/from.cpp (100%) rename {test_static_asserts => tests/core/static_asserts}/having.cpp (100%) rename {test_static_asserts => tests/core/static_asserts}/in.cpp (100%) rename {test_static_asserts => tests/core/static_asserts}/insert.cpp (100%) rename {test_static_asserts => tests/core/static_asserts}/join.cpp (100%) rename {test_static_asserts => tests/core/static_asserts}/no_self_compare.cpp (100%) rename {test_static_asserts => tests/core/static_asserts}/text.cpp (100%) rename {test_static_asserts => tests/core/static_asserts}/unwrapped_bool.cpp (100%) rename {test_static_asserts => tests/core/static_asserts}/update_list.cpp (100%) rename {test_static_asserts => tests/core/static_asserts}/where.cpp (100%) rename tests/{ => core/usage}/BooleanExpression.cpp (100%) create mode 100644 tests/core/usage/CMakeLists.txt rename tests/{ => core/usage}/CustomQuery.cpp (100%) rename tests/{ => core/usage}/DateTime.cpp (100%) rename tests/{ => core/usage}/Function.cpp (100%) rename tests/{ => core/usage}/Insert.cpp (100%) rename tests/{ => core/usage}/Interpret.cpp (100%) rename tests/{ => core/usage}/Minimalistic.cpp (100%) rename tests/{ => core/usage}/MockDb.h (100%) rename tests/{ => core/usage}/Ppgen.cpp (100%) rename tests/{ => core/usage}/Prepared.cpp (100%) rename tests/{ => core/usage}/Remove.cpp (100%) rename tests/{ => core/usage}/Result.cpp (100%) rename tests/{ => core/usage}/Sample.h (100%) rename tests/{ => core/usage}/Select.cpp (100%) rename tests/{ => core/usage}/SelectType.cpp (100%) rename tests/{ => core/usage}/Union.cpp (100%) rename tests/{ => core/usage}/Update.cpp (100%) rename tests/{ => core/usage}/With.cpp (100%) rename tests/{ => core/usage}/is_regular.h (100%) rename tests/{ => core/usage}/sample.sql (100%) create mode 100644 tests/sqlite3/CMakeLists.txt create mode 100644 tests/sqlite3/usage/AttachTest.cpp create mode 100644 tests/sqlite3/usage/AutoIncrementTest.cpp create mode 100644 tests/sqlite3/usage/BlobSample.h create mode 100644 tests/sqlite3/usage/BlobSample.sql create mode 100644 tests/sqlite3/usage/BlobTest.cpp create mode 100644 tests/sqlite3/usage/CMakeLists.txt create mode 100644 tests/sqlite3/usage/DateTimeTest.cpp create mode 100644 tests/sqlite3/usage/DynamicLoadingTest.cpp create mode 100644 tests/sqlite3/usage/DynamicSelectTest.cpp create mode 100644 tests/sqlite3/usage/FloatingPointTest.cpp create mode 100644 tests/sqlite3/usage/FpSample.h create mode 100644 tests/sqlite3/usage/FpSample.sql create mode 100644 tests/sqlite3/usage/IntegralSample.h create mode 100644 tests/sqlite3/usage/IntegralTest.cpp create mode 100644 tests/sqlite3/usage/SampleTest.cpp create mode 100644 tests/sqlite3/usage/SelectTest.cpp create mode 100644 tests/sqlite3/usage/TabSample.h create mode 100644 tests/sqlite3/usage/TabSample.sql create mode 100644 tests/sqlite3/usage/TransactionTest.cpp create mode 100644 tests/sqlite3/usage/UnionTest.cpp create mode 100644 tests/sqlite3/usage/WithTest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a2fe7818..849669c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2016, Roland Bock +# Copyright (c) 2013-2021, Roland Bock # Copyright (c) 2016 Christian Dávid # All rights reserved. # @@ -27,6 +27,35 @@ cmake_minimum_required(VERSION 3.14) project(sqlpp11 VERSION 0.1 LANGUAGES CXX) +option(MYSQL_CONNECTOR "Build MySQL Connector" OFF) +option(POSTGRESQL_CONNECTOR "Build PostgreSQL Connector" OFF) +option(SQLITE3_CONNECTOR "Build SQLite3 Connector" OFF) +option(SQLCIPHER_CONNECTOR "Build SQLite3 Connector with SQLCipher" OFF) + +if(MYSQL_CONNECTOR) + find_package(MySQL REQUIRED) +else() + message(STATUS "Not building MYSQL_CONNECTOR") +endif() + +if(POSTGRESQL_CONNECTOR) + find_package(PostgreSQL REQUIRED) +else() + message(STATUS "Not building POSTGRESQL_CONNECTOR") +endif() + +if(SQLITE3_CONNECTOR) + find_package(SQLite3 REQUIRED) +else() + message(STATUS "Not building SQLITE3_CONNECTOR") +endif() + +if(SQLCIPHER_CONNECTOR) + find_package(SQLCipher REQUIRED) +else() + message(STATUS "Not building SQLCIPHER_CONNECTOR") +endif() + ### Project Wide Setup list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") @@ -44,10 +73,13 @@ endif() ### Dependencies add_subdirectory(dependencies) -### Main targets +### Core targets add_library(sqlpp11 INTERFACE) add_library(sqlpp11::sqlpp11 ALIAS sqlpp11) +# Connector targets +add_subdirectory(src) + target_link_libraries(sqlpp11 INTERFACE date::date) target_include_directories(sqlpp11 INTERFACE @@ -127,8 +159,5 @@ install( if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) add_subdirectory(tests) add_subdirectory(test_types) - add_subdirectory(test_serializer) - add_subdirectory(test_static_asserts) - add_subdirectory(test_constraints) add_subdirectory(test_scripts) endif() diff --git a/include/sqlpp11/sqlite3/bind_result.h b/include/sqlpp11/sqlite3/bind_result.h new file mode 100644 index 00000000..f72403aa --- /dev/null +++ b/include/sqlpp11/sqlite3/bind_result.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2013 - 2015, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_SQLITE3_BIND_RESULT_H +#define SQLPP_SQLITE3_BIND_RESULT_H + +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4251) +#endif + +namespace sqlpp +{ + namespace sqlite3 + { + namespace detail + { + struct prepared_statement_handle_t; + } + + class SQLPP11_SQLITE3_EXPORT bind_result_t + { + std::shared_ptr _handle; + + public: + bind_result_t() = default; + bind_result_t(const std::shared_ptr& handle); + bind_result_t(const bind_result_t&) = delete; + bind_result_t(bind_result_t&& rhs) = default; + bind_result_t& operator=(const bind_result_t&) = delete; + bind_result_t& operator=(bind_result_t&&) = default; + ~bind_result_t() = default; + + bool operator==(const bind_result_t& rhs) const + { + return _handle == rhs._handle; + } + + template + void next(ResultRow& result_row) + { + if (!_handle) + { + result_row._invalidate(); + return; + } + + if (next_impl()) + { + if (not result_row) + { + result_row._validate(); + } + result_row._bind(*this); + } + else + { + if (result_row) + result_row._invalidate(); + } + } + + void _bind_boolean_result(size_t index, signed char* value, bool* is_null); + void _bind_floating_point_result(size_t index, double* value, bool* is_null); + void _bind_integral_result(size_t index, int64_t* value, bool* is_null); + void _bind_unsigned_integral_result(size_t index, uint64_t* value, bool* is_null); + void _bind_text_result(size_t index, const char** text, size_t* len); + void _bind_blob_result(size_t index, const uint8_t** text, size_t* len); + void _bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null); + void _bind_date_time_result(size_t index, ::sqlpp::chrono::microsecond_point* value, bool* is_null); + + private: + bool next_impl(); + }; + } // namespace sqlite3 +} // namespace sqlpp + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif diff --git a/include/sqlpp11/sqlite3/connection.h b/include/sqlpp11/sqlite3/connection.h new file mode 100644 index 00000000..709ee098 --- /dev/null +++ b/include/sqlpp11/sqlite3/connection.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_SQLITE3_CONNECTION_H +#define SQLPP_SQLITE3_CONNECTION_H + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +namespace sqlpp +{ + namespace sqlite3 + { + namespace detail + { + struct connection_handle; + } + + class connection; + + struct serializer_t + { + serializer_t(const connection& db) : _db(db), _count(1) + { + } + + template + std::ostream& operator<<(T t) + { + return _os << t; + } + + std::string escape(std::string arg); + + std::string str() const + { + return _os.str(); + } + + size_t count() const + { + return _count; + } + + void pop_count() + { + ++_count; + } + + const connection& _db; + std::stringstream _os; + size_t _count; + }; + + class SQLPP11_SQLITE3_EXPORT connection : public sqlpp::connection + { + std::unique_ptr _handle; + enum class transaction_status_type + { + none, + maybe, + active + }; + + transaction_status_type _transaction_status = transaction_status_type::none; + + // direct execution + bind_result_t select_impl(const std::string& statement); + size_t insert_impl(const std::string& statement); + size_t update_impl(const std::string& statement); + size_t remove_impl(const std::string& statement); + + // prepared execution + prepared_statement_t prepare_impl(const std::string& statement); + bind_result_t run_prepared_select_impl(prepared_statement_t& prepared_statement); + size_t run_prepared_execute_impl(prepared_statement_t& prepared_statement); + size_t run_prepared_insert_impl(prepared_statement_t& prepared_statement); + size_t run_prepared_update_impl(prepared_statement_t& prepared_statement); + size_t run_prepared_remove_impl(prepared_statement_t& prepared_statement); + + public: + using _prepared_statement_t = prepared_statement_t; + using _context_t = serializer_t; + using _serializer_context_t = _context_t; + using _interpreter_context_t = _context_t; + + struct _tags + { + using _null_result_is_trivial_value = std::true_type; + }; + + template + static _context_t& _serialize_interpretable(const T& t, _context_t& context) + { + return ::sqlpp::serialize(t, context); + } + + template + static _context_t& _interpret_interpretable(const T& t, _context_t& context) + { + return ::sqlpp::serialize(t, context); + } + + connection(connection_config config); + connection(connection&&) noexcept; + connection& operator=(connection&&) noexcept; + ~connection(); + connection(const connection&) = delete; + connection& operator=(const connection&) = delete; + + //! select returns a result (which can be iterated row by row) + template + bind_result_t select(const Select& s) + { + _context_t context(*this); + serialize(s, context); + return select_impl(context.str()); + } + + template + _prepared_statement_t prepare_select(Select& s) + { + _context_t context(*this); + serialize(s, context); + return prepare_impl(context.str()); + } + + template + bind_result_t run_prepared_select(const PreparedSelect& s) + { + s._prepared_statement._reset(); + s._bind_params(); + return run_prepared_select_impl(s._prepared_statement); + } + + //! insert returns the last auto_incremented id (or zero, if there is none) + template + size_t insert(const Insert& i) + { + _context_t context(*this); + serialize(i, context); + return insert_impl(context.str()); + } + + template + _prepared_statement_t prepare_insert(Insert& i) + { + _context_t context(*this); + serialize(i, context); + return prepare_impl(context.str()); + } + + template + size_t run_prepared_insert(const PreparedInsert& i) + { + i._prepared_statement._reset(); + i._bind_params(); + return run_prepared_insert_impl(i._prepared_statement); + } + + //! update returns the number of affected rows + template + size_t update(const Update& u) + { + _context_t context(*this); + serialize(u, context); + return update_impl(context.str()); + } + + template + _prepared_statement_t prepare_update(Update& u) + { + _context_t context(*this); + serialize(u, context); + return prepare_impl(context.str()); + } + + template + size_t run_prepared_update(const PreparedUpdate& u) + { + u._prepared_statement._reset(); + u._bind_params(); + return run_prepared_update_impl(u._prepared_statement); + } + + //! remove returns the number of removed rows + template + size_t remove(const Remove& r) + { + _context_t context(*this); + serialize(r, context); + return remove_impl(context.str()); + } + + template + _prepared_statement_t prepare_remove(Remove& r) + { + _context_t context(*this); + serialize(r, context); + return prepare_impl(context.str()); + } + + template + size_t run_prepared_remove(const PreparedRemove& r) + { + r._prepared_statement._reset(); + r._bind_params(); + return run_prepared_remove_impl(r._prepared_statement); + } + + //! execute arbitrary command (e.g. create a table) + size_t execute(const std::string& command); + + template < + typename Execute, + typename Enable = typename std::enable_if::value, void>::type> + size_t execute(const Execute& x) + { + _context_t context(*this); + serialize(x, context); + return execute(context.str()); + } + + template + _prepared_statement_t prepare_execute(Execute& x) + { + _context_t context(*this); + serialize(x, context); + return prepare_impl(context.str()); + } + + template + size_t run_prepared_execute(const PreparedExecute& x) + { + x._prepared_statement._reset(); + x._bind_params(); + return run_prepared_execute_impl(x._prepared_statement); + } + + //! escape given string (does not quote, though) + std::string escape(const std::string& s) const; + + //! call run on the argument + template + auto _run(const T& t, ::sqlpp::consistent_t) -> decltype(t._run(*this)) + { + return t._run(*this); + } + + template + auto _run(const T& t, Check) -> Check; + + template + auto operator()(const T& t) -> decltype(this->_run(t, sqlpp::run_check_t<_serializer_context_t, T>{})) + { + return _run(t, sqlpp::run_check_t<_serializer_context_t, T>{}); + } + + //! call prepare on the argument + template + auto _prepare(const T& t, const std::true_type&) -> decltype(t._prepare(*this)) + { + return t._prepare(*this); + } + + template + auto _prepare(const T& t, const std::false_type&) -> void; + + template + auto prepare(const T& t) + -> decltype(this->_prepare(t, typename sqlpp::prepare_check_t<_serializer_context_t, T>::type{})) + { + sqlpp::prepare_check_t<_serializer_context_t, T>{}; + return _prepare(t, sqlpp::prepare_check_t<_serializer_context_t, T>{}); + } + + //! set the transaction isolation level for this connection + void set_default_isolation_level(isolation_level level); + + //! get the currently active transaction isolation level + isolation_level get_default_isolation_level(); + + //! start transaction + void start_transaction(); + + //! commit transaction (or throw if the transaction has been finished already) + void commit_transaction(); + + //! rollback transaction with or without reporting the rollback (or throw if the transaction has been finished + // already) + void rollback_transaction(bool report); + + //! report a rollback failure (will be called by transactions in case of a rollback failure in the destructor) + void report_rollback_failure(const std::string message) noexcept; + + //! get the last inserted id + uint64_t last_insert_id() noexcept; + + ::sqlite3* native_handle(); + + auto attach(const connection_config&, const std::string name) -> schema_t; + }; + + inline std::string serializer_t::escape(std::string arg) + { + return _db.escape(arg); + } + } // namespace sqlite3 +} // namespace sqlpp + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include + +#endif diff --git a/include/sqlpp11/sqlite3/connection_config.h b/include/sqlpp11/sqlite3/connection_config.h new file mode 100644 index 00000000..1affb84e --- /dev/null +++ b/include/sqlpp11/sqlite3/connection_config.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_SQLITE3_CONNECTION_CONFIG_H +#define SQLPP_SQLITE3_CONNECTION_CONFIG_H + +#include +#include + +namespace sqlpp +{ + namespace sqlite3 + { + struct connection_config + { + connection_config() : path_to_database(), flags(0), vfs(), debug(false),password("") + { + } + connection_config(const connection_config&) = default; + connection_config(connection_config&&) = default; + + connection_config(std::string path, int fl = 0, std::string vf = "", bool dbg = false,std::string password="") + : path_to_database(std::move(path)), flags(fl), vfs(std::move(vf)), debug(dbg),password(password) + { + } + + bool operator==(const connection_config& other) const + { + return (other.path_to_database == path_to_database && other.flags == flags && other.vfs == vfs && + other.debug == debug && other.password==password); + } + + bool operator!=(const connection_config& other) const + { + return !operator==(other); + } + + + std::string path_to_database; + int flags; + std::string vfs; + bool debug; + std::string password; + }; + } +} + +#endif diff --git a/include/sqlpp11/sqlite3/dynamic_libsqlite3.h b/include/sqlpp11/sqlite3/dynamic_libsqlite3.h new file mode 100644 index 00000000..c5e4ecd7 --- /dev/null +++ b/include/sqlpp11/sqlite3/dynamic_libsqlite3.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2017, Volker Aßmann + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef DYNAMIC_LIBSQLITE3_H +#define DYNAMIC_LIBSQLITE3_H + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include + +// namespace for internal sqlite function wrappers - when using this instead of sqlite3 direct linking +// do this: +// using namespace sqlpp::sqlite3::dyn; +// to override the libsqlite3 functions with these function pointers + +#ifdef SQLPP_DYNAMIC_LOADING + +namespace sqlpp +{ + namespace sqlite3 + { + namespace dynamic + { + /// load the SQLite libraries, optionally providing the filename (leave empty for default) + void init_sqlite(std::string libname); + +#define DYNDEFINE(NAME) extern decltype(::NAME)* NAME + + DYNDEFINE(sqlite3_open_v2); + DYNDEFINE(sqlite3_open); + DYNDEFINE(sqlite3_prepare_v2); + DYNDEFINE(sqlite3_exec); + DYNDEFINE(sqlite3_step); + DYNDEFINE(sqlite3_bind_int); + DYNDEFINE(sqlite3_close); + DYNDEFINE(sqlite3_initialize); + DYNDEFINE(sqlite3_os_init); + DYNDEFINE(sqlite3_os_end); + DYNDEFINE(sqlite3_bind_blob); + DYNDEFINE(sqlite3_bind_double); + DYNDEFINE(sqlite3_bind_int64); + DYNDEFINE(sqlite3_bind_null); + DYNDEFINE(sqlite3_bind_text); + DYNDEFINE(sqlite3_bind_value); + DYNDEFINE(sqlite3_libversion_number); + // DYNDEFINE(sqlite3_compileoption_used); + DYNDEFINE(sqlite3_threadsafe); + // DYNDEFINE(sqlite3_close_v2); + DYNDEFINE(sqlite3_shutdown); + DYNDEFINE(sqlite3_config); + DYNDEFINE(sqlite3_db_config); + DYNDEFINE(sqlite3_extended_result_codes); + DYNDEFINE(sqlite3_last_insert_rowid); + DYNDEFINE(sqlite3_changes); + DYNDEFINE(sqlite3_total_changes); + DYNDEFINE(sqlite3_interrupt); + DYNDEFINE(sqlite3_complete); + DYNDEFINE(sqlite3_complete16); + DYNDEFINE(sqlite3_busy_handler); + DYNDEFINE(sqlite3_busy_timeout); + DYNDEFINE(sqlite3_get_table); + DYNDEFINE(sqlite3_free_table); + // DYNDEFINE(sqlite3_realloc64); + DYNDEFINE(sqlite3_free); + // DYNDEFINE(sqlite3_msize); + DYNDEFINE(sqlite3_memory_used); + DYNDEFINE(sqlite3_memory_highwater); + DYNDEFINE(sqlite3_randomness); + DYNDEFINE(sqlite3_set_authorizer); + DYNDEFINE(sqlite3_progress_handler); + DYNDEFINE(sqlite3_open16); + // DYNDEFINE(sqlite3_uri_boolean); + // DYNDEFINE(sqlite3_uri_int64); + DYNDEFINE(sqlite3_errcode); + DYNDEFINE(sqlite3_errmsg); + DYNDEFINE(sqlite3_extended_errcode); + DYNDEFINE(sqlite3_limit); + DYNDEFINE(sqlite3_prepare); + DYNDEFINE(sqlite3_prepare16); + DYNDEFINE(sqlite3_prepare16_v2); + // DYNDEFINE(sqlite3_stmt_readonly); + // DYNDEFINE(sqlite3_stmt_busy); + // DYNDEFINE(sqlite3_bind_blob64); + DYNDEFINE(sqlite3_bind_text16); + // DYNDEFINE(sqlite3_bind_text64); + DYNDEFINE(sqlite3_bind_zeroblob); + DYNDEFINE(sqlite3_bind_parameter_count); + DYNDEFINE(sqlite3_bind_parameter_index); + DYNDEFINE(sqlite3_clear_bindings); + DYNDEFINE(sqlite3_column_count); + DYNDEFINE(sqlite3_data_count); + DYNDEFINE(sqlite3_column_bytes); + DYNDEFINE(sqlite3_column_bytes16); + DYNDEFINE(sqlite3_column_double); + DYNDEFINE(sqlite3_column_int); + DYNDEFINE(sqlite3_column_int64); + DYNDEFINE(sqlite3_column_text); + DYNDEFINE(sqlite3_column_type); + DYNDEFINE(sqlite3_column_value); + DYNDEFINE(sqlite3_column_blob); + DYNDEFINE(sqlite3_finalize); + DYNDEFINE(sqlite3_reset); + DYNDEFINE(sqlite3_create_function); + DYNDEFINE(sqlite3_create_function16); + // DYNDEFINE(sqlite3_create_function_v2); + DYNDEFINE(sqlite3_value_bytes); + DYNDEFINE(sqlite3_value_bytes16); + DYNDEFINE(sqlite3_value_double); + DYNDEFINE(sqlite3_value_int); + DYNDEFINE(sqlite3_value_int64); + DYNDEFINE(sqlite3_value_type); + DYNDEFINE(sqlite3_value_numeric_type); + DYNDEFINE(sqlite3_set_auxdata); + DYNDEFINE(sqlite3_result_blob); + // DYNDEFINE(sqlite3_result_blob64); + DYNDEFINE(sqlite3_result_double); + DYNDEFINE(sqlite3_result_error); + DYNDEFINE(sqlite3_result_error16); + DYNDEFINE(sqlite3_result_error_toobig); + DYNDEFINE(sqlite3_result_error_nomem); + DYNDEFINE(sqlite3_result_error_code); + DYNDEFINE(sqlite3_result_int); + DYNDEFINE(sqlite3_result_int64); + DYNDEFINE(sqlite3_result_null); + DYNDEFINE(sqlite3_result_text); + // DYNDEFINE(sqlite3_result_text64); + DYNDEFINE(sqlite3_result_text16); + DYNDEFINE(sqlite3_result_text16le); + DYNDEFINE(sqlite3_result_text16be); + DYNDEFINE(sqlite3_result_value); + DYNDEFINE(sqlite3_result_zeroblob); + DYNDEFINE(sqlite3_create_collation); + DYNDEFINE(sqlite3_create_collation_v2); + DYNDEFINE(sqlite3_create_collation16); + DYNDEFINE(sqlite3_collation_needed); + DYNDEFINE(sqlite3_collation_needed16); + +#ifdef SQLITE_HAS_CODEC + + DYNDEFINE(sqlite3_key); + DYNDEFINE(sqlite3_key_v2); + DYNDEFINE(sqlite3_rekey); + DYNDEFINE(sqlite3_rekey_v2); + DYNDEFINE(sqlite3_activate_see); +#endif +#ifdef SQLITE_ENABLE_CEROD + DYNDEFINE(sqlite3_activate_cerod); +#endif + DYNDEFINE(sqlite3_sleep); + DYNDEFINE(sqlite3_get_autocommit); + // DYNDEFINE(sqlite3_db_readonly); + DYNDEFINE(sqlite3_next_stmt); + DYNDEFINE(sqlite3_enable_shared_cache); + DYNDEFINE(sqlite3_release_memory); + // DYNDEFINE(sqlite3_db_release_memory); + // DYNDEFINE(sqlite3_soft_heap_limit64); + DYNDEFINE(sqlite3_table_column_metadata); + DYNDEFINE(sqlite3_load_extension); + DYNDEFINE(sqlite3_enable_load_extension); + DYNDEFINE(sqlite3_auto_extension); + // DYNDEFINE(sqlite3_cancel_auto_extension); + DYNDEFINE(sqlite3_reset_auto_extension); + DYNDEFINE(sqlite3_create_module); + DYNDEFINE(sqlite3_create_module_v2); + DYNDEFINE(sqlite3_declare_vtab); + DYNDEFINE(sqlite3_overload_function); + DYNDEFINE(sqlite3_blob_open); + DYNDEFINE(sqlite3_blob_close); + DYNDEFINE(sqlite3_blob_bytes); + DYNDEFINE(sqlite3_blob_read); + DYNDEFINE(sqlite3_blob_write); + DYNDEFINE(sqlite3_vfs_find); + DYNDEFINE(sqlite3_vfs_register); + DYNDEFINE(sqlite3_vfs_unregister); + DYNDEFINE(sqlite3_mutex_alloc); + DYNDEFINE(sqlite3_mutex_free); + DYNDEFINE(sqlite3_mutex_enter); + DYNDEFINE(sqlite3_mutex_try); + DYNDEFINE(sqlite3_mutex_leave); + // DYNDEFINE(sqlite3_mutex_held); + // DYNDEFINE(sqlite3_mutex_notheld); + DYNDEFINE(sqlite3_db_mutex); + DYNDEFINE(sqlite3_file_control); + DYNDEFINE(sqlite3_test_control); + DYNDEFINE(sqlite3_status); + DYNDEFINE(sqlite3_db_status); + DYNDEFINE(sqlite3_stmt_status); + DYNDEFINE(sqlite3_backup_init); + DYNDEFINE(sqlite3_backup_step); + DYNDEFINE(sqlite3_backup_finish); + DYNDEFINE(sqlite3_backup_remaining); + DYNDEFINE(sqlite3_backup_pagecount); + DYNDEFINE(sqlite3_unlock_notify); + // DYNDEFINE(sqlite3_stricmp); + // DYNDEFINE(sqlite3_strnicmp); + // DYNDEFINE(sqlite3_strglob); + // DYNDEFINE(sqlite3_log); + // DYNDEFINE(sqlite3_wal_autocheckpoint); + // DYNDEFINE(sqlite3_wal_checkpoint); + // DYNDEFINE(sqlite3_wal_checkpoint_v2); + // DYNDEFINE(sqlite3_vtab_config); + // DYNDEFINE(sqlite3_vtab_on_conflict); + // DYNDEFINE(sqlite3_rtree_geometry_callback); + // DYNDEFINE(sqlite3_rtree_query_callback); + } // namespace dynamic + } // namespace sqlite3 +} // namespace sqlpp + +#undef DYNDEFINE + +#endif +#endif // DYNAMIC_LIBSQLITE3_H diff --git a/include/sqlpp11/sqlite3/export.h b/include/sqlpp11/sqlite3/export.h new file mode 100644 index 00000000..4f387562 --- /dev/null +++ b/include/sqlpp11/sqlite3/export.h @@ -0,0 +1,18 @@ +#ifndef SQLPP_SQLITE3_EXPORT_H +#define SQLPP_SQLITE3_EXPORT_H + +#ifdef _WIN32 + #ifdef SQLPP11_SHARED + #ifdef SQLPP11_COMPILING_DLL + #define SQLPP11_SQLITE3_EXPORT __declspec(dllexport) + #else + #define SQLPP11_SQLITE3_EXPORT __declspec(dllimport) + #endif + #else + #define SQLPP11_SQLITE3_EXPORT + #endif +#else + #define SQLPP11_SQLITE3_EXPORT +#endif + +#endif diff --git a/include/sqlpp11/sqlite3/insert_or.h b/include/sqlpp11/sqlite3/insert_or.h new file mode 100644 index 00000000..bbd92706 --- /dev/null +++ b/include/sqlpp11/sqlite3/insert_or.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2013 - 2015, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_SQLITE3_INSERT_OR_H +#define SQLPP_SQLITE3_INSERT_OR_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sqlpp +{ + namespace sqlite3 + { + struct insert_or_replace_name_t + { + }; + struct insert_or_ignore_name_t + { + }; + + template + struct insert_or_t : public statement_name_t + { + using _traits = make_traits; + struct _alias_t + { + }; + + template + struct _result_methods_t + { + using _statement_t = Statement; + + const _statement_t& _get_statement() const + { + return static_cast(*this); + } + + template + auto _run(Db& db) const -> decltype(db.insert(this->_get_statement())) + { + return db.insert(_get_statement()); + } + + template + auto _prepare(Db& db) const -> prepared_insert_t + { + return {{}, db.prepare_insert(_get_statement())}; + } + }; + }; + + template + using blank_insert_or_t = + statement_t, no_into_t, no_insert_value_list_t>; + + template + using blank_insert_or_replace_t = blank_insert_or_t; + + template + using blank_insert_or_ignore_t = blank_insert_or_t; + + inline auto insert_or_replace() -> blank_insert_or_replace_t + { + return {blank_insert_or_replace_t()}; + } + + template + constexpr auto insert_or_replace_into(Table table) -> decltype(blank_insert_or_replace_t().into(table)) + { + return {blank_insert_or_replace_t().into(table)}; + } + + template + constexpr auto dynamic_insert_or_replace(const Database&) -> decltype(blank_insert_or_replace_t()) + { + return {blank_insert_or_replace_t()}; + } + + template + constexpr auto dynamic_insert_or_replace_into(const Database&, Table table) + -> decltype(blank_insert_or_replace_t().into(table)) + { + return {blank_insert_or_replace_t().into(table)}; + } + + inline auto insert_or_ignore() -> blank_insert_or_ignore_t + { + return {blank_insert_or_ignore_t()}; + } + + template + constexpr auto insert_or_ignore_into(Table table) -> decltype(blank_insert_or_ignore_t().into(table)) + { + return {blank_insert_or_ignore_t().into(table)}; + } + + template + constexpr auto dynamic_insert_or_ignore(const Database&) -> decltype(blank_insert_or_ignore_t()) + { + return {blank_insert_or_ignore_t()}; + } + + template + constexpr auto dynamic_insert_or_ignore_into(const Database&, Table table) + -> decltype(blank_insert_or_ignore_t().into(table)) + { + return {blank_insert_or_ignore_t().into(table)}; + } + + inline sqlite3::serializer_t& serialize(const sqlite3::insert_or_replace_name_t&, sqlite3::serializer_t& context) + { + context << "INSERT OR REPLACE "; + return context; + } + + inline sqlite3::serializer_t& serialize(const sqlite3::insert_or_ignore_name_t&, sqlite3::serializer_t& context) + { + context << "INSERT OR IGNORE "; + return context; + } + } +} + +#endif diff --git a/include/sqlpp11/sqlite3/prepared_statement.h b/include/sqlpp11/sqlite3/prepared_statement.h new file mode 100644 index 00000000..2497c979 --- /dev/null +++ b/include/sqlpp11/sqlite3/prepared_statement.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013 - 2015, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_SQLITE3_PREPARED_STATEMENT_H +#define SQLPP_SQLITE3_PREPARED_STATEMENT_H + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4251) +#endif + +namespace sqlpp +{ + namespace sqlite3 + { + class connection; + + namespace detail + { + struct prepared_statement_handle_t; + } + + class SQLPP11_SQLITE3_EXPORT prepared_statement_t + { + friend ::sqlpp::sqlite3::connection; + std::shared_ptr _handle; + + public: + prepared_statement_t() = default; + prepared_statement_t(std::shared_ptr&& handle); + prepared_statement_t(const prepared_statement_t&) = delete; + prepared_statement_t(prepared_statement_t&& rhs) = default; + prepared_statement_t& operator=(const prepared_statement_t&) = delete; + prepared_statement_t& operator=(prepared_statement_t&&) = default; + ~prepared_statement_t() = default; + + bool operator==(const prepared_statement_t& rhs) const + { + return _handle == rhs._handle; + } + + void _reset(); + void _bind_boolean_parameter(size_t index, const signed char* value, bool is_null); + void _bind_floating_point_parameter(size_t index, const double* value, bool is_null); + void _bind_integral_parameter(size_t index, const int64_t* value, bool is_null); + void _bind_unsigned_integral_parameter(size_t index, const uint64_t* value, bool is_null); + void _bind_text_parameter(size_t index, const std::string* value, bool is_null); + void _bind_date_parameter(size_t index, const ::sqlpp::chrono::day_point* value, bool is_null); + void _bind_date_time_parameter(size_t index, const ::sqlpp::chrono::microsecond_point* value, bool is_null); + void _bind_blob_parameter(size_t index, const std::vector* value, bool is_null); + }; + } // namespace sqlite3 +} // namespace sqlpp + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif diff --git a/include/sqlpp11/sqlite3/serializer.h b/include/sqlpp11/sqlite3/serializer.h new file mode 100644 index 00000000..9b71f2f1 --- /dev/null +++ b/include/sqlpp11/sqlite3/serializer.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_SQLITE3_SERIALIZER_H +#define SQLPP_SQLITE3_SERIALIZER_H + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace sqlpp +{ + // Serialize parameters + template + sqlite3::serializer_t& serialize(const parameter_t&, sqlite3::serializer_t& context) + { + context << "?" << context.count(); + context.pop_count(); + return context; + } + + // disable some stuff that won't work with sqlite3 +#if SQLITE_VERSION_NUMBER < 3008003 + template + sqlite3::serializer_t& serialize(const with_data_t&, sqlite3::serializer_t& context) + { + static_assert(wrong_t::value, "Sqlite3: No support for with before version 3.8.3"); + return context; + } +#endif + + template + sqlite3::serializer_t& serialize(const any_t::value, "Sqlite3: No support for any()"); + return context; + } + + template + sqlite3::serializer_t& serialize(const some_t::value, "Sqlite3: No support for some()"); + return context; + } + + template + sqlite3::serializer_t& serialize(const pre_join_t&, sqlite3::serializer_t& context) + { + static_assert(wrong_t::value, "Sqlite3: No support for outer join"); + return context; + }; + + template + sqlite3::serializer_t& serialize(const pre_join_t&, sqlite3::serializer_t& context) + { + static_assert(wrong_t::value, "Sqlite3: No support for right_outer join"); + return context; + }; + + // Some special treatment of data types + template + sqlite3::serializer_t& serialize(const time_point_operand& t, sqlite3::serializer_t& context) + { + const auto dp = ::sqlpp::chrono::floor<::date::days>(t._t); + const auto time = ::date::make_time(t._t - dp); + const auto ymd = ::date::year_month_day{dp}; + context << "STRFTIME('%Y-%m-%d %H:%M:%f', '" << ymd << ' ' << time << "')"; + return context; + } + + inline sqlite3::serializer_t& serialize(const day_point_operand& t, sqlite3::serializer_t& context) + { + const auto ymd = ::date::year_month_day{t._t}; + context << "DATE('" << ymd << "')"; + return context; + } + + inline sqlite3::serializer_t& serialize(const floating_point_operand& t, sqlite3::serializer_t& context) + { + if (std::isnan(t._t)) + context << "'NaN'"; + else if (std::isinf(t._t)) + { + if (t._t > std::numeric_limits::max()) + context << "'Inf'"; + else + context << "'-Inf'"; + } + else + context << t._t; + return context; + } + + // sqlite3 accepts only signed integers, + // so we MUST perform a conversion from unsigned to signed + inline sqlite3::serializer_t& serialize(const unsigned_integral_operand& t, sqlite3::serializer_t& context) + { + context << static_cast(t._t); + return context; + } +} + +#endif diff --git a/include/sqlpp11/sqlite3/sqlite3.h b/include/sqlpp11/sqlite3/sqlite3.h new file mode 100644 index 00000000..2a033ad1 --- /dev/null +++ b/include/sqlpp11/sqlite3/sqlite3.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013 - 2015, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_SQLITE3_H +#define SQLPP_SQLITE3_H + +#include +#include + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..3df596c3 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright (c) 2021-2021, Roland Bock +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +if(MYSQL_CONNECTOR) + add_subdirectory(mysql) +endif() + +if(POSTGRESQL_CONNECTOR) + add_subdirectory(postgresql) +endif() + +if(SQLITE3_CONNECTOR OR SQLCIPHER_CONNECTOR) + add_subdirectory(sqlite3) +endif() + diff --git a/src/sqlite3/CMakeLists.txt b/src/sqlite3/CMakeLists.txt new file mode 100644 index 00000000..22cc1062 --- /dev/null +++ b/src/sqlite3/CMakeLists.txt @@ -0,0 +1,96 @@ +# Copyright (c) 2013 - 2016, Roland Bock +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) + +add_library(sqlpp11-connector-sqlite3) +add_library(sqlpp11::sqlite3 ALIAS sqlpp11-connector-sqlite3) + +target_sources(sqlpp11-connector-sqlite3 + PRIVATE + connection.cpp + bind_result.cpp + prepared_statement.cpp + detail/connection_handle.cpp +) +target_link_libraries(sqlpp11-connector-sqlite3 PUBLIC sqlpp11::sqlpp11) + +if (SQLPP_DYNAMIC_LOADING) + add_library(sqlpp11-connector-sqlite3-dynamic + connection.cpp + bind_result.cpp + prepared_statement.cpp + detail/connection_handle.cpp + detail/dynamic_libsqlite3.cpp + ) + add_library(sqlpp11::sqlite3-dynamic ALIAS sqlpp11-connector-sqlite3-dynamic) + + get_filename_component(SQLite3_LIB_FILE ${SQLite3_LIBRARY} NAME) + + if (WIN32) + # the import library (.lib) needs to be replaced by .dll + get_filename_component(SQLite3_LIB_FILE ${SQLite3_LIB_FILE} NAME_WE) + string(APPEND SQLite3_LIB_FILE ".dll") + endif() + + set_target_properties(sqlpp11-connector-sqlite3 PROPERTIES DEFINE_SYMBOL SQLPP11_COMPILING_DLL) + set_target_properties(sqlpp11-connector-sqlite3-dynamic PROPERTIES DEFINE_SYMBOL SQLPP11_COMPILING_DLL) + + target_compile_definitions(sqlpp11-connector-sqlite3-dynamic + PUBLIC SQLPP_DYNAMIC_LOADING + PRIVATE SQLPP_DYNAMIC_LOADING_FILENAME=${SQLite3_LIB_FILE}) + + target_include_directories(sqlpp11-connector-sqlite3-dynamic PUBLIC + $ + $) + + target_link_libraries(sqlpp11-connector-sqlite3-dynamic PUBLIC sqlpp11::sqlpp11) +endif() + +target_include_directories(sqlpp11-connector-sqlite3 PUBLIC + $ + $) + +if (SQLCIPHER) + target_compile_definitions(sqlpp11-connector-sqlite3 PUBLIC SQLPP_USE_SQLCIPHER) + target_link_libraries(sqlpp11-connector-sqlite3 PUBLIC SQLCipher::SQLCipher) + if (SQLPP_DYNAMIC_LOADING) + target_compile_definitions(sqlpp11-connector-sqlite3-dynamic PUBLIC SQLPP_USE_SQLCIPHER) + target_include_directories(sqlpp11-connector-sqlite3-dynamic PUBLIC ${SQLCIPHER_INCLUDE_DIRS}) + endif() +else() + target_link_libraries(sqlpp11-connector-sqlite3 PUBLIC SQLite::SQLite3) +endif() + +install(TARGETS sqlpp11-connector-sqlite3 + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin) + +if (SQLPP_DYNAMIC_LOADING) + install(TARGETS sqlpp11-connector-sqlite3-dynamic + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin) +endif() diff --git a/src/sqlite3/bind_result.cpp b/src/sqlite3/bind_result.cpp new file mode 100644 index 00000000..0385cf86 --- /dev/null +++ b/src/sqlite3/bind_result.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "detail/prepared_statement_handle.h" +#include +#include +#include // Howard Hinnant's date library +#include +#include +#include +#include + +#ifdef SQLPP_DYNAMIC_LOADING +#include +#endif + +namespace sqlpp +{ + namespace sqlite3 + { +#ifdef SQLPP_DYNAMIC_LOADING + using namespace dynamic; +#endif + + bind_result_t::bind_result_t(const std::shared_ptr& handle) : _handle(handle) + { + if (_handle and _handle->debug) + std::cerr << "Sqlite3 debug: Constructing bind result, using handle at " << _handle.get() << std::endl; + } + + void bind_result_t::_bind_boolean_result(size_t index, signed char* value, bool* is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding boolean result " << *value << " at index: " << index << std::endl; + + *value = static_cast(sqlite3_column_int(_handle->sqlite_statement, static_cast(index))); + *is_null = sqlite3_column_type(_handle->sqlite_statement, static_cast(index)) == SQLITE_NULL; + } + + void bind_result_t::_bind_floating_point_result(size_t index, double* value, bool* is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding floating_point result " << *value << " at index: " << index << std::endl; + + switch (sqlite3_column_type(_handle->sqlite_statement, static_cast(index))) + { + case (SQLITE3_TEXT): + *value = atof( + reinterpret_cast(sqlite3_column_text(_handle->sqlite_statement, static_cast(index)))); + break; + default: + *value = sqlite3_column_double(_handle->sqlite_statement, static_cast(index)); + } + *is_null = sqlite3_column_type(_handle->sqlite_statement, static_cast(index)) == SQLITE_NULL; + } + + void bind_result_t::_bind_integral_result(size_t index, int64_t* value, bool* is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding integral result " << *value << " at index: " << index << std::endl; + + *value = sqlite3_column_int64(_handle->sqlite_statement, static_cast(index)); + *is_null = sqlite3_column_type(_handle->sqlite_statement, static_cast(index)) == SQLITE_NULL; + } + + void bind_result_t::_bind_unsigned_integral_result(size_t index, uint64_t* value, bool* is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding unsigned integral result " << *value << " at index: " << index + << std::endl; + + *value = static_cast(sqlite3_column_int64(_handle->sqlite_statement, static_cast(index))); + *is_null = sqlite3_column_type(_handle->sqlite_statement, static_cast(index)) == SQLITE_NULL; + } + + void bind_result_t::_bind_text_result(size_t index, const char** value, size_t* len) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding text result at index: " << index << std::endl; + + *value = (reinterpret_cast(sqlite3_column_text(_handle->sqlite_statement, static_cast(index)))); + *len = sqlite3_column_bytes(_handle->sqlite_statement, static_cast(index)); + } + + void bind_result_t::_bind_blob_result(size_t index, const uint8_t** value, size_t* len) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding text result at index: " << index << std::endl; + + *value = + (reinterpret_cast(sqlite3_column_blob(_handle->sqlite_statement, static_cast(index)))); + *len = sqlite3_column_bytes(_handle->sqlite_statement, static_cast(index)); + } + + namespace + { + const auto date_digits = std::vector{1, 1, 1, 1, 0, 1, 1, 0, 1, 1}; // 2015-10-28 + const auto time_digits = std::vector{0, 1, 1, 0, 1, 1, 0, 1, 1}; // T23:00:12 + const auto ms_digits = std::vector{0, 1, 1, 1}; // .123 + + auto check_digits(const char* text, const std::vector& digitFlags) -> bool + { + for (const auto digitFlag : digitFlags) + { + if (digitFlag) + { + if (not std::isdigit(*text)) + { + return false; + } + } + else + { + if (std::isdigit(*text) or *text == '\0') + { + return false; + } + } + ++text; + } + return true; + } + } // namespace + + void bind_result_t::_bind_date_result(size_t index, ::sqlpp::chrono::day_point* value, bool* is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding date result at index: " << index << std::endl; + + *is_null = sqlite3_column_type(_handle->sqlite_statement, static_cast(index)) == SQLITE_NULL; + if (*is_null) + { + *value = {}; + return; + } + + const auto date_string = + reinterpret_cast(sqlite3_column_text(_handle->sqlite_statement, static_cast(index))); + if (_handle->debug) + std::cerr << "Sqlite3 debug: date string: " << date_string << std::endl; + + if (check_digits(date_string, date_digits)) + { + const auto ymd = ::date::year(std::atoi(date_string)) / atoi(date_string + 5) / atoi(date_string + 8); + *value = ::sqlpp::chrono::day_point(ymd); + } + else + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: invalid date result: " << date_string << std::endl; + *value = {}; + } + } + + void bind_result_t::_bind_date_time_result(size_t index, ::sqlpp::chrono::microsecond_point* value, bool* is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding date result at index: " << index << std::endl; + + *is_null = sqlite3_column_type(_handle->sqlite_statement, static_cast(index)) == SQLITE_NULL; + if (*is_null) + { + *value = {}; + return; + } + + const auto date_time_string = + reinterpret_cast(sqlite3_column_text(_handle->sqlite_statement, static_cast(index))); + if (_handle->debug) + std::cerr << "Sqlite3 debug: date_time string: " << date_time_string << std::endl; + + if (check_digits(date_time_string, date_digits)) + { + const auto ymd = + ::date::year(std::atoi(date_time_string)) / atoi(date_time_string + 5) / atoi(date_time_string + 8); + *value = ::sqlpp::chrono::day_point(ymd); + } + else + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: invalid date_time result: " << date_time_string << std::endl; + *value = {}; + + return; + } + + const auto time_string = date_time_string + 10; + if (check_digits(time_string, time_digits)) + { + *value += ::std::chrono::hours(std::atoi(time_string + 1)) + std::chrono::minutes(std::atoi(time_string + 4)) + + std::chrono::seconds(std::atoi(time_string + 7)); + } + else + { + return; + } + const auto ms_string = time_string + 9; + if (check_digits(ms_string, ms_digits) and ms_string[4] == '\0') + { + *value += ::std::chrono::milliseconds(std::atoi(ms_string + 1)); + } + else + { + return; + } + } + + bool bind_result_t::next_impl() + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: Accessing next row of handle at " << _handle.get() << std::endl; + + auto rc = sqlite3_step(_handle->sqlite_statement); + + switch (rc) + { + case SQLITE_ROW: + return true; + case SQLITE_DONE: + return false; + default: + throw sqlpp::exception("Sqlite3 error: Unexpected return value for sqlite3_step()"); + } + } + } // namespace sqlite3 +} // namespace sqlpp diff --git a/src/sqlite3/connection.cpp b/src/sqlite3/connection.cpp new file mode 100644 index 00000000..ab5305e4 --- /dev/null +++ b/src/sqlite3/connection.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "detail/connection_handle.h" +#include "detail/prepared_statement_handle.h" +#include +#include +#include + +#ifdef SQLPP_DYNAMIC_LOADING +#include +#endif + +namespace sqlpp +{ + namespace sqlite3 + { + +#ifdef SQLPP_DYNAMIC_LOADING + using namespace dynamic; +#endif + + namespace + { + detail::prepared_statement_handle_t prepare_statement(detail::connection_handle& handle, + const std::string& statement) + { + if (handle.config.debug) + std::cerr << "Sqlite3 debug: Preparing: '" << statement << "'" << std::endl; + + detail::prepared_statement_handle_t result(nullptr, handle.config.debug); + + auto rc = sqlite3_prepare_v2(handle.sqlite, statement.c_str(), static_cast(statement.size()), + &result.sqlite_statement, nullptr); + + if (rc != SQLITE_OK) + { + throw sqlpp::exception("Sqlite3 error: Could not prepare statement: " + + std::string(sqlite3_errmsg(handle.sqlite)) + " (statement was >>" + + (rc == SQLITE_TOOBIG ? statement.substr(0, 128) + "..." : statement) + + "<<\n"); + } + + return result; + } + + void execute_statement(detail::connection_handle& handle, detail::prepared_statement_handle_t& prepared) + { + auto rc = sqlite3_step(prepared.sqlite_statement); + switch (rc) + { + case SQLITE_OK: + case SQLITE_ROW: // might occur if execute is called with a select + case SQLITE_DONE: + return; + default: + if(handle.config.debug) + std::cerr << "Sqlite3 debug: sqlite3_step return code: " << rc << std::endl; + throw sqlpp::exception("Sqlite3 error: Could not execute statement: " + + std::string(sqlite3_errmsg(handle.sqlite))); + } + } + } + + connection::connection(connection_config config) : _handle(new detail::connection_handle(std::move(config))) + { + } + + connection::connection(connection&&) noexcept = default; + connection& connection::operator=(connection&&) noexcept = default; + + connection::~connection() + { + } + + ::sqlite3* connection::native_handle() + { + return _handle->sqlite; + } + + bind_result_t connection::select_impl(const std::string& statement) + { + std::unique_ptr prepared( + new detail::prepared_statement_handle_t(prepare_statement(*_handle, statement))); + if (!prepared) + { + throw sqlpp::exception("Sqlite3 error: Could not store result set"); + } + + return {std::move(prepared)}; + } + + bind_result_t connection::run_prepared_select_impl(prepared_statement_t& prepared_statement) + { + return {prepared_statement._handle}; + } + + size_t connection::insert_impl(const std::string& statement) + { + auto prepared = prepare_statement(*_handle, statement); + execute_statement(*_handle, prepared); + + return sqlite3_last_insert_rowid(_handle->sqlite); + } + + prepared_statement_t connection::prepare_impl(const std::string& statement) + { + return {std::unique_ptr( + new detail::prepared_statement_handle_t(prepare_statement(*_handle, statement)))}; + } + + size_t connection::run_prepared_insert_impl(prepared_statement_t& prepared_statement) + { + execute_statement(*_handle, *prepared_statement._handle.get()); + + return sqlite3_last_insert_rowid(_handle->sqlite); + } + + size_t connection::run_prepared_execute_impl(prepared_statement_t& prepared_statement) + { + execute_statement(*_handle, *prepared_statement._handle.get()); + + return sqlite3_changes(_handle->sqlite); + } + + size_t connection::execute(const std::string& statement) + { + auto prepared = prepare_statement(*_handle, statement); + execute_statement(*_handle, prepared); + return sqlite3_changes(_handle->sqlite); + } + + size_t connection::update_impl(const std::string& statement) + { + auto prepared = prepare_statement(*_handle, statement); + execute_statement(*_handle, prepared); + return sqlite3_changes(_handle->sqlite); + } + + size_t connection::run_prepared_update_impl(prepared_statement_t& prepared_statement) + { + execute_statement(*_handle, *prepared_statement._handle.get()); + + return sqlite3_changes(_handle->sqlite); + } + + size_t connection::remove_impl(const std::string& statement) + { + auto prepared = prepare_statement(*_handle, statement); + execute_statement(*_handle, prepared); + return sqlite3_changes(_handle->sqlite); + } + + size_t connection::run_prepared_remove_impl(prepared_statement_t& prepared_statement) + { + execute_statement(*_handle, *prepared_statement._handle.get()); + + return sqlite3_changes(_handle->sqlite); + } + + std::string connection::escape(const std::string& s) const + { + std::string t; + t.reserve(s.size()); + + for (const char c : s) + { + if (c == '\'') + t.push_back(c); + t.push_back(c); + } + + return t; + } + + void connection::set_default_isolation_level(isolation_level level) + { + if (level == sqlpp::isolation_level::read_uncommitted) + { + execute("pragma read_uncommitted = true"); + } else { + execute("pragma read_uncommitted = false"); + } + } + + sqlpp::isolation_level connection::get_default_isolation_level() + { + auto stmt = prepare_statement(*_handle, "pragma read_uncommitted"); + execute_statement(*_handle, stmt); + + int level = sqlite3_column_int(stmt.sqlite_statement, 0); + + return level == 0 ? sqlpp::isolation_level::serializable : + sqlpp::isolation_level::read_uncommitted; + } + + void connection::start_transaction() + { + if (_transaction_status == transaction_status_type::active) + { + throw sqlpp::exception("Sqlite3 error: Cannot have more than one open transaction per connection"); + } + + _transaction_status = transaction_status_type::maybe; + auto prepared = prepare_statement(*_handle, "BEGIN"); + execute_statement(*_handle, prepared); + _transaction_status = transaction_status_type::active; + } + + void connection::commit_transaction() + { + if (_transaction_status == transaction_status_type::none) + { + throw sqlpp::exception("Sqlite3 error: Cannot commit a finished or failed transaction"); + } + _transaction_status = transaction_status_type::maybe; + auto prepared = prepare_statement(*_handle, "COMMIT"); + execute_statement(*_handle, prepared); + _transaction_status = transaction_status_type::none; + } + + void connection::rollback_transaction(bool report) + { + if (_transaction_status == transaction_status_type::none) + { + throw sqlpp::exception("Sqlite3 error: Cannot rollback a finished or failed transaction"); + } + if (report) + { + std::cerr << "Sqlite3 warning: Rolling back unfinished transaction" << std::endl; + } + _transaction_status = transaction_status_type::maybe; + auto prepared = prepare_statement(*_handle, "ROLLBACK"); + execute_statement(*_handle, prepared); + _transaction_status = transaction_status_type::none; + } + + void connection::report_rollback_failure(const std::string message) noexcept + { + std::cerr << "Sqlite3 message:" << message << std::endl; + } + + uint64_t connection::last_insert_id() noexcept + { + return sqlite3_last_insert_rowid(_handle->sqlite); + } + + auto connection::attach(const connection_config& config, const std::string name) -> schema_t + { + auto prepared = + prepare_statement(*_handle, "ATTACH '" + escape(config.path_to_database) + "' AS " + escape(name)); + execute_statement(*_handle, prepared); + + return {name}; + } + } +} diff --git a/src/sqlite3/detail/connection_handle.cpp b/src/sqlite3/detail/connection_handle.cpp new file mode 100644 index 00000000..9466632b --- /dev/null +++ b/src/sqlite3/detail/connection_handle.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2013 - 2015, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include "connection_handle.h" + +#ifdef SQLPP_DYNAMIC_LOADING +#include +#endif + +namespace sqlpp +{ + namespace sqlite3 + { + +#ifdef SQLPP_DYNAMIC_LOADING + using namespace dynamic; +#endif + + namespace detail + { + connection_handle::connection_handle(connection_config conf) : config(conf), sqlite(nullptr) + { +#ifdef SQLPP_DYNAMIC_LOADING + init_sqlite(""); +#endif + + auto rc = sqlite3_open_v2(conf.path_to_database.c_str(), &sqlite, conf.flags, + conf.vfs.empty() ? nullptr : conf.vfs.c_str()); + if (rc != SQLITE_OK) + { + const std::string msg = sqlite3_errmsg(sqlite); + sqlite3_close(sqlite); + throw sqlpp::exception("Sqlite3 error: Can't open database: " + msg); + } +#ifdef SQLITE_HAS_CODEC + if (conf.password.size()>0) + { + int ret = sqlite3_key(sqlite, conf.password.data(),conf.password.size()); + if (ret!=SQLITE_OK) + { + const std::string msg = sqlite3_errmsg(sqlite); + sqlite3_close(sqlite); + throw sqlpp::exception("Sqlite3 error: Can't set password to database: " + msg); + } + } +#endif + } + + connection_handle::~connection_handle() + { + auto rc = sqlite3_close(sqlite); + if (rc != SQLITE_OK) + { + std::cerr << "Sqlite3 error: Can't close database: " << sqlite3_errmsg(sqlite) << std::endl; + } + } + } + } +} diff --git a/src/sqlite3/detail/connection_handle.h b/src/sqlite3/detail/connection_handle.h new file mode 100644 index 00000000..3a8a4bf1 --- /dev/null +++ b/src/sqlite3/detail/connection_handle.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_SQLITE3_CONNECTION_HANDLE_H +#define SQLPP_SQLITE3_CONNECTION_HANDLE_H + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include + +namespace sqlpp +{ + namespace sqlite3 + { + struct connection_config; + + namespace detail + { + struct connection_handle + { + connection_config config; + ::sqlite3* sqlite; + + connection_handle(connection_config config); + ~connection_handle(); + connection_handle(const connection_handle&) = delete; + connection_handle(connection_handle&&) = delete; + connection_handle& operator=(const connection_handle&) = delete; + connection_handle& operator=(connection_handle&&) = delete; + }; + } // namespace detail + } // namespace sqlite3 +} // namespace sqlpp + +#endif diff --git a/src/sqlite3/detail/dynamic_libsqlite3.cpp b/src/sqlite3/detail/dynamic_libsqlite3.cpp new file mode 100644 index 00000000..3f02975d --- /dev/null +++ b/src/sqlite3/detail/dynamic_libsqlite3.cpp @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2017, Volker Assmann + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sqlpp11/sqlite3/dynamic_libsqlite3.h" +#include "sqlpp11/exception.h" + +#include +#include + +#if defined(__linux__) || defined(__APPLE__) +#include +#else +#include +#endif + +#ifdef SQLPP_DYNAMIC_LOADING + +namespace sqlpp +{ + namespace sqlite3 + { + namespace dynamic + { +#define DYNDEFINE(NAME) decltype(::NAME)* NAME + +#if defined(__linux__) || defined(__APPLE__) +#define DYNLOAD(HNDL, NAME) NAME = reinterpret_cast(dlsym(HNDL, #NAME)) +#else +#define DYNLOAD(HNDL, NAME) NAME = reinterpret_cast(GetProcAddress(HNDL, #NAME)) +#endif + + DYNDEFINE(sqlite3_open_v2); + DYNDEFINE(sqlite3_open); + DYNDEFINE(sqlite3_prepare_v2); + DYNDEFINE(sqlite3_exec); + DYNDEFINE(sqlite3_step); + DYNDEFINE(sqlite3_bind_int); + DYNDEFINE(sqlite3_close); + DYNDEFINE(sqlite3_initialize); + DYNDEFINE(sqlite3_os_init); + DYNDEFINE(sqlite3_os_end); + DYNDEFINE(sqlite3_bind_blob); + DYNDEFINE(sqlite3_bind_double); + DYNDEFINE(sqlite3_bind_int64); + DYNDEFINE(sqlite3_bind_null); + DYNDEFINE(sqlite3_bind_text); + DYNDEFINE(sqlite3_bind_value); + DYNDEFINE(sqlite3_libversion_number); + // DYNDEFINE(sqlite3_compileoption_used); + DYNDEFINE(sqlite3_threadsafe); + // DYNDEFINE(sqlite3_close_v2); + DYNDEFINE(sqlite3_shutdown); + DYNDEFINE(sqlite3_config); + DYNDEFINE(sqlite3_db_config); + DYNDEFINE(sqlite3_extended_result_codes); + DYNDEFINE(sqlite3_last_insert_rowid); + DYNDEFINE(sqlite3_changes); + DYNDEFINE(sqlite3_total_changes); + DYNDEFINE(sqlite3_interrupt); + DYNDEFINE(sqlite3_complete); + DYNDEFINE(sqlite3_complete16); + DYNDEFINE(sqlite3_busy_handler); + DYNDEFINE(sqlite3_busy_timeout); + DYNDEFINE(sqlite3_get_table); + DYNDEFINE(sqlite3_free_table); + // DYNDEFINE(sqlite3_realloc64); + DYNDEFINE(sqlite3_free); + // DYNDEFINE(sqlite3_msize); + DYNDEFINE(sqlite3_memory_used); + DYNDEFINE(sqlite3_memory_highwater); + DYNDEFINE(sqlite3_randomness); + DYNDEFINE(sqlite3_set_authorizer); + DYNDEFINE(sqlite3_progress_handler); + DYNDEFINE(sqlite3_open16); + // DYNDEFINE(sqlite3_uri_boolean); + // DYNDEFINE(sqlite3_uri_int64); + DYNDEFINE(sqlite3_errcode); + DYNDEFINE(sqlite3_errmsg); + DYNDEFINE(sqlite3_extended_errcode); + DYNDEFINE(sqlite3_limit); + DYNDEFINE(sqlite3_prepare); + DYNDEFINE(sqlite3_prepare16); + DYNDEFINE(sqlite3_prepare16_v2); + // DYNDEFINE(sqlite3_stmt_readonly); + // DYNDEFINE(sqlite3_stmt_busy); + // DYNDEFINE(sqlite3_bind_blob64); + DYNDEFINE(sqlite3_bind_text16); + // DYNDEFINE(sqlite3_bind_text64); + DYNDEFINE(sqlite3_bind_zeroblob); + DYNDEFINE(sqlite3_bind_parameter_count); + DYNDEFINE(sqlite3_bind_parameter_index); + DYNDEFINE(sqlite3_clear_bindings); + DYNDEFINE(sqlite3_column_count); + DYNDEFINE(sqlite3_data_count); + DYNDEFINE(sqlite3_column_bytes); + DYNDEFINE(sqlite3_column_bytes16); + DYNDEFINE(sqlite3_column_double); + DYNDEFINE(sqlite3_column_int); + DYNDEFINE(sqlite3_column_int64); + DYNDEFINE(sqlite3_column_text); + DYNDEFINE(sqlite3_column_type); + DYNDEFINE(sqlite3_column_value); + DYNDEFINE(sqlite3_column_blob); + DYNDEFINE(sqlite3_finalize); + DYNDEFINE(sqlite3_reset); + DYNDEFINE(sqlite3_create_function); + DYNDEFINE(sqlite3_create_function16); + // DYNDEFINE(sqlite3_create_function_v2); + DYNDEFINE(sqlite3_value_bytes); + DYNDEFINE(sqlite3_value_bytes16); + DYNDEFINE(sqlite3_value_double); + DYNDEFINE(sqlite3_value_int); + DYNDEFINE(sqlite3_value_int64); + DYNDEFINE(sqlite3_value_type); + DYNDEFINE(sqlite3_value_numeric_type); + DYNDEFINE(sqlite3_set_auxdata); + DYNDEFINE(sqlite3_result_blob); + // DYNDEFINE(sqlite3_result_blob64); + DYNDEFINE(sqlite3_result_double); + DYNDEFINE(sqlite3_result_error); + DYNDEFINE(sqlite3_result_error16); + DYNDEFINE(sqlite3_result_error_toobig); + DYNDEFINE(sqlite3_result_error_nomem); + DYNDEFINE(sqlite3_result_error_code); + DYNDEFINE(sqlite3_result_int); + DYNDEFINE(sqlite3_result_int64); + DYNDEFINE(sqlite3_result_null); + DYNDEFINE(sqlite3_result_text); + // DYNDEFINE(sqlite3_result_text64); + DYNDEFINE(sqlite3_result_text16); + DYNDEFINE(sqlite3_result_text16le); + DYNDEFINE(sqlite3_result_text16be); + DYNDEFINE(sqlite3_result_value); + DYNDEFINE(sqlite3_result_zeroblob); + DYNDEFINE(sqlite3_create_collation); + DYNDEFINE(sqlite3_create_collation_v2); + DYNDEFINE(sqlite3_create_collation16); + DYNDEFINE(sqlite3_collation_needed); + DYNDEFINE(sqlite3_collation_needed16); + +#ifdef SQLITE_HAS_CODEC + + DYNDEFINE(sqlite3_key); + DYNDEFINE(sqlite3_key_v2); + DYNDEFINE(sqlite3_rekey); + DYNDEFINE(sqlite3_rekey_v2); + DYNDEFINE(sqlite3_activate_see); +#endif +#ifdef SQLITE_ENABLE_CEROD + DYNDEFINE(sqlite3_activate_cerod); +#endif + DYNDEFINE(sqlite3_sleep); + DYNDEFINE(sqlite3_get_autocommit); + // DYNDEFINE(sqlite3_db_readonly); + DYNDEFINE(sqlite3_next_stmt); + DYNDEFINE(sqlite3_enable_shared_cache); + DYNDEFINE(sqlite3_release_memory); + // DYNDEFINE(sqlite3_db_release_memory); + // DYNDEFINE(sqlite3_soft_heap_limit64); + DYNDEFINE(sqlite3_table_column_metadata); + DYNDEFINE(sqlite3_load_extension); + DYNDEFINE(sqlite3_enable_load_extension); + DYNDEFINE(sqlite3_auto_extension); + // DYNDEFINE(sqlite3_cancel_auto_extension); + DYNDEFINE(sqlite3_reset_auto_extension); + DYNDEFINE(sqlite3_create_module); + DYNDEFINE(sqlite3_create_module_v2); + DYNDEFINE(sqlite3_declare_vtab); + DYNDEFINE(sqlite3_overload_function); + DYNDEFINE(sqlite3_blob_open); + DYNDEFINE(sqlite3_blob_close); + DYNDEFINE(sqlite3_blob_bytes); + DYNDEFINE(sqlite3_blob_read); + DYNDEFINE(sqlite3_blob_write); + DYNDEFINE(sqlite3_vfs_find); + DYNDEFINE(sqlite3_vfs_register); + DYNDEFINE(sqlite3_vfs_unregister); + DYNDEFINE(sqlite3_mutex_alloc); + DYNDEFINE(sqlite3_mutex_free); + DYNDEFINE(sqlite3_mutex_enter); + DYNDEFINE(sqlite3_mutex_try); + DYNDEFINE(sqlite3_mutex_leave); + // DYNDEFINE(sqlite3_mutex_held); + // DYNDEFINE(sqlite3_mutex_notheld); + DYNDEFINE(sqlite3_db_mutex); + DYNDEFINE(sqlite3_file_control); + DYNDEFINE(sqlite3_test_control); + DYNDEFINE(sqlite3_status); + DYNDEFINE(sqlite3_db_status); + DYNDEFINE(sqlite3_stmt_status); + DYNDEFINE(sqlite3_backup_init); + DYNDEFINE(sqlite3_backup_step); + DYNDEFINE(sqlite3_backup_finish); + DYNDEFINE(sqlite3_backup_remaining); + DYNDEFINE(sqlite3_backup_pagecount); + DYNDEFINE(sqlite3_unlock_notify); +// DYNDEFINE(sqlite3_stricmp); +// DYNDEFINE(sqlite3_strnicmp); +// DYNDEFINE(sqlite3_strglob); +// DYNDEFINE(sqlite3_log); +// DYNDEFINE(sqlite3_wal_autocheckpoint); +// DYNDEFINE(sqlite3_wal_checkpoint); +// DYNDEFINE(sqlite3_wal_checkpoint_v2); +// DYNDEFINE(sqlite3_vtab_config); +// DYNDEFINE(sqlite3_vtab_on_conflict); +// DYNDEFINE(sqlite3_rtree_geometry_callback); +// DYNDEFINE(sqlite3_rtree_query_callback); + +#define STR(x) #x +#define GET_STR(x) STR(x) + +#ifndef SQLPP_DYNAMIC_LOADING_FILENAME +#ifdef __linux__ +#define SQLPP_DYNAMIC_LOADING_FILENAME libsqlite3.so +#elif __APPLE__ +#define SQLPP_DYNAMIC_LOADING_FILENAME libsqlite3.dylib +#endif +#endif + + void init_sqlite(std::string libname) + { + if (libname.empty()) + { + libname = GET_STR(SQLPP_DYNAMIC_LOADING_FILENAME); + } +#if defined(__linux__) || defined(__APPLE__) + void* handle = nullptr; + handle = dlopen(libname.c_str(), RTLD_LAZY | RTLD_GLOBAL); +#else + HINSTANCE handle = nullptr; + handle = LoadLibrary(libname.c_str()); +#endif + +#undef STR +#undef GET_STR + + if (!handle) + { +#if defined(__linux__) || defined(__APPLE__) + throw sqlpp::exception(std::string("Could not load library " + libname + ": ").append(dlerror())); +#elif defined(_WIN32) + if (GetLastError() == 193) + { + throw sqlpp::exception( + "Could not load SQLite library - error code indicates you are mixing 32/64 bit DLLs (lib: " + libname + + ")"); + } + else + { + throw sqlpp::exception("Could not load lib using LoadLibrary (" + libname + ")"); + } +#endif + } + + DYNLOAD(handle, sqlite3_libversion_number); + // DYNLOAD(handle, sqlite3_compileoption_used); + DYNLOAD(handle, sqlite3_threadsafe); + DYNLOAD(handle, sqlite3_close); + // DYNLOAD(handle, sqlite3_close_v2); + DYNLOAD(handle, sqlite3_exec); + DYNLOAD(handle, sqlite3_initialize); + DYNLOAD(handle, sqlite3_shutdown); + DYNLOAD(handle, sqlite3_os_init); + DYNLOAD(handle, sqlite3_os_end); + DYNLOAD(handle, sqlite3_config); + DYNLOAD(handle, sqlite3_db_config); + DYNLOAD(handle, sqlite3_extended_result_codes); + DYNLOAD(handle, sqlite3_last_insert_rowid); + DYNLOAD(handle, sqlite3_changes); + DYNLOAD(handle, sqlite3_total_changes); + DYNLOAD(handle, sqlite3_interrupt); + DYNLOAD(handle, sqlite3_complete); + DYNLOAD(handle, sqlite3_complete16); + DYNLOAD(handle, sqlite3_busy_handler); + DYNLOAD(handle, sqlite3_busy_timeout); + DYNLOAD(handle, sqlite3_get_table); + DYNLOAD(handle, sqlite3_free_table); + // DYNLOAD(handle, sqlite3_realloc64); + DYNLOAD(handle, sqlite3_free); + // DYNLOAD(handle, sqlite3_msize); + DYNLOAD(handle, sqlite3_memory_used); + DYNLOAD(handle, sqlite3_memory_highwater); + DYNLOAD(handle, sqlite3_randomness); + DYNLOAD(handle, sqlite3_set_authorizer); + DYNLOAD(handle, sqlite3_progress_handler); + DYNLOAD(handle, sqlite3_open); + DYNLOAD(handle, sqlite3_open16); + DYNLOAD(handle, sqlite3_open_v2); + // DYNLOAD(handle, sqlite3_uri_boolean); + // DYNLOAD(handle, sqlite3_uri_int64); + DYNLOAD(handle, sqlite3_errcode); + DYNLOAD(handle, sqlite3_errmsg); + DYNLOAD(handle, sqlite3_extended_errcode); + DYNLOAD(handle, sqlite3_limit); + DYNLOAD(handle, sqlite3_prepare); + DYNLOAD(handle, sqlite3_prepare_v2); + DYNLOAD(handle, sqlite3_prepare16); + DYNLOAD(handle, sqlite3_prepare16_v2); + // DYNLOAD(handle, sqlite3_stmt_readonly); + // DYNLOAD(handle, sqlite3_stmt_busy); + DYNLOAD(handle, sqlite3_bind_blob); + // DYNLOAD(handle, sqlite3_bind_blob64); + DYNLOAD(handle, sqlite3_bind_double); + DYNLOAD(handle, sqlite3_bind_int); + DYNLOAD(handle, sqlite3_bind_int64); + DYNLOAD(handle, sqlite3_bind_null); + DYNLOAD(handle, sqlite3_bind_text); + DYNLOAD(handle, sqlite3_bind_text16); + // DYNLOAD(handle, sqlite3_bind_text64); + DYNLOAD(handle, sqlite3_bind_value); + DYNLOAD(handle, sqlite3_bind_zeroblob); + DYNLOAD(handle, sqlite3_bind_parameter_count); + DYNLOAD(handle, sqlite3_bind_parameter_index); + DYNLOAD(handle, sqlite3_clear_bindings); + DYNLOAD(handle, sqlite3_column_count); + DYNLOAD(handle, sqlite3_step); + DYNLOAD(handle, sqlite3_data_count); + DYNLOAD(handle, sqlite3_column_bytes); + DYNLOAD(handle, sqlite3_column_bytes16); + DYNLOAD(handle, sqlite3_column_double); + DYNLOAD(handle, sqlite3_column_int); + DYNLOAD(handle, sqlite3_column_int64); + DYNLOAD(handle, sqlite3_column_text); + DYNLOAD(handle, sqlite3_column_type); + DYNLOAD(handle, sqlite3_column_value); + DYNLOAD(handle, sqlite3_column_blob); + DYNLOAD(handle, sqlite3_finalize); + DYNLOAD(handle, sqlite3_reset); + DYNLOAD(handle, sqlite3_create_function); + DYNLOAD(handle, sqlite3_create_function16); + // DYNLOAD(handle, sqlite3_create_function_v2); + DYNLOAD(handle, sqlite3_value_bytes); + DYNLOAD(handle, sqlite3_value_bytes16); + DYNLOAD(handle, sqlite3_value_double); + DYNLOAD(handle, sqlite3_value_int); + DYNLOAD(handle, sqlite3_value_int64); + DYNLOAD(handle, sqlite3_value_type); + DYNLOAD(handle, sqlite3_value_numeric_type); + DYNLOAD(handle, sqlite3_set_auxdata); + DYNLOAD(handle, sqlite3_result_blob); + // DYNLOAD(handle, sqlite3_result_blob64); + DYNLOAD(handle, sqlite3_result_double); + DYNLOAD(handle, sqlite3_result_error); + DYNLOAD(handle, sqlite3_result_error16); + DYNLOAD(handle, sqlite3_result_error_toobig); + DYNLOAD(handle, sqlite3_result_error_nomem); + DYNLOAD(handle, sqlite3_result_error_code); + DYNLOAD(handle, sqlite3_result_int); + DYNLOAD(handle, sqlite3_result_int64); + DYNLOAD(handle, sqlite3_result_null); + DYNLOAD(handle, sqlite3_result_text); + // DYNLOAD(handle, sqlite3_result_text64); + DYNLOAD(handle, sqlite3_result_text16); + DYNLOAD(handle, sqlite3_result_text16le); + DYNLOAD(handle, sqlite3_result_text16be); + DYNLOAD(handle, sqlite3_result_value); + DYNLOAD(handle, sqlite3_result_zeroblob); + DYNLOAD(handle, sqlite3_create_collation); + DYNLOAD(handle, sqlite3_create_collation_v2); + DYNLOAD(handle, sqlite3_create_collation16); + DYNLOAD(handle, sqlite3_collation_needed); + DYNLOAD(handle, sqlite3_collation_needed16); + +#ifdef SQLITE_HAS_CODEC + DYNLOAD(handle, sqlite3_key); + DYNLOAD(handle, sqlite3_key_v2); + DYNLOAD(handle, sqlite3_rekey); + DYNLOAD(handle, sqlite3_rekey_v2); + DYNLOAD(handle, sqlite3_activate_see); +#endif +#ifdef SQLITE_ENABLE_CEROD + DYNLOAD(handle, sqlite3_activate_cerod); +#endif + DYNLOAD(handle, sqlite3_sleep); + DYNLOAD(handle, sqlite3_get_autocommit); + // DYNLOAD(handle, sqlite3_db_readonly); + DYNLOAD(handle, sqlite3_next_stmt); + DYNLOAD(handle, sqlite3_enable_shared_cache); + DYNLOAD(handle, sqlite3_release_memory); + // DYNLOAD(handle, sqlite3_db_release_memory); + // DYNLOAD(handle, sqlite3_soft_heap_limit64); + DYNLOAD(handle, sqlite3_table_column_metadata); + DYNLOAD(handle, sqlite3_load_extension); + DYNLOAD(handle, sqlite3_enable_load_extension); + DYNLOAD(handle, sqlite3_auto_extension); + // DYNLOAD(handle, sqlite3_cancel_auto_extension); + DYNLOAD(handle, sqlite3_reset_auto_extension); + DYNLOAD(handle, sqlite3_create_module); + DYNLOAD(handle, sqlite3_create_module_v2); + DYNLOAD(handle, sqlite3_declare_vtab); + DYNLOAD(handle, sqlite3_overload_function); + DYNLOAD(handle, sqlite3_blob_open); + DYNLOAD(handle, sqlite3_blob_close); + DYNLOAD(handle, sqlite3_blob_bytes); + DYNLOAD(handle, sqlite3_blob_read); + DYNLOAD(handle, sqlite3_blob_write); + DYNLOAD(handle, sqlite3_vfs_find); + DYNLOAD(handle, sqlite3_vfs_register); + DYNLOAD(handle, sqlite3_vfs_unregister); + DYNLOAD(handle, sqlite3_mutex_alloc); + DYNLOAD(handle, sqlite3_mutex_free); + DYNLOAD(handle, sqlite3_mutex_enter); + DYNLOAD(handle, sqlite3_mutex_try); + DYNLOAD(handle, sqlite3_mutex_leave); + // DYNLOAD(handle, sqlite3_mutex_held); + // DYNLOAD(handle, sqlite3_mutex_notheld); + DYNLOAD(handle, sqlite3_db_mutex); + DYNLOAD(handle, sqlite3_file_control); + DYNLOAD(handle, sqlite3_test_control); + DYNLOAD(handle, sqlite3_status); + DYNLOAD(handle, sqlite3_db_status); + DYNLOAD(handle, sqlite3_stmt_status); + DYNLOAD(handle, sqlite3_backup_init); + DYNLOAD(handle, sqlite3_backup_step); + DYNLOAD(handle, sqlite3_backup_finish); + DYNLOAD(handle, sqlite3_backup_remaining); + DYNLOAD(handle, sqlite3_backup_pagecount); + DYNLOAD(handle, sqlite3_unlock_notify); + // DYNLOAD(handle, sqlite3_stricmp); + // DYNLOAD(handle, sqlite3_strnicmp); + // DYNLOAD(handle, sqlite3_strglob); + // DYNLOAD(handle, sqlite3_log); + // DYNLOAD(handle, sqlite3_wal_autocheckpoint); + // DYNLOAD(handle, sqlite3_wal_checkpoint); + // DYNLOAD(handle, sqlite3_wal_checkpoint_v2); + // DYNLOAD(handle, sqlite3_vtab_config); + // DYNLOAD(handle, sqlite3_vtab_on_conflict); + // DYNLOAD(handle, sqlite3_rtree_geometry_callback); + // DYNLOAD(handle, sqlite3_rtree_query_callback); + + // check some functions for nullptr to verify if loading worked, otherwise throw + if (sqlite3_shutdown == nullptr || sqlite3_exec == nullptr) + { + throw sqlpp::exception("Initializing dynamically loaded SQLite3 functions failed"); + } + } + } // dynamic + } // sqlite3 +} // sqlpp + +#undef DYNDEFINE +#undef DYNLOAD +#endif diff --git a/src/sqlite3/detail/prepared_statement_handle.h b/src/sqlite3/detail/prepared_statement_handle.h new file mode 100644 index 00000000..fad66475 --- /dev/null +++ b/src/sqlite3/detail/prepared_statement_handle.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013 - 2015, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_SQLITE3_DETAIL_PREPARED_STATEMENT_HANDLE_H +#define SQLPP_SQLITE3_DETAIL_PREPARED_STATEMENT_HANDLE_H + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif + +#ifdef SQLPP_DYNAMIC_LOADING +#include +#endif + +namespace sqlpp +{ + namespace sqlite3 + { +#ifdef SQLPP_DYNAMIC_LOADING + using namespace dynamic; +#endif + namespace detail + { + struct prepared_statement_handle_t + { + sqlite3_stmt* sqlite_statement; + bool debug; + + prepared_statement_handle_t(sqlite3_stmt* statement, bool debug_) : sqlite_statement(statement), debug(debug_) + { + } + + prepared_statement_handle_t(const prepared_statement_handle_t&) = delete; + prepared_statement_handle_t(prepared_statement_handle_t&& rhs) + { + sqlite_statement = rhs.sqlite_statement; + rhs.sqlite_statement = nullptr; + + debug = rhs.debug; + } + prepared_statement_handle_t& operator=(const prepared_statement_handle_t&) = delete; + prepared_statement_handle_t& operator=(prepared_statement_handle_t&& rhs) + { + if (sqlite_statement != rhs.sqlite_statement) + { + sqlite_statement = rhs.sqlite_statement; + rhs.sqlite_statement = nullptr; + } + debug = rhs.debug; + + return *this; + } + + ~prepared_statement_handle_t() + { + if (sqlite_statement) + { + sqlite3_finalize(sqlite_statement); + } + } + + bool operator!() const + { + return !sqlite_statement; + } + }; + } // namespace detail + } // namespace sqlite3 +} // namespace sqlpp + +#endif diff --git a/src/sqlite3/prepared_statement.cpp b/src/sqlite3/prepared_statement.cpp new file mode 100644 index 00000000..5d4b85e8 --- /dev/null +++ b/src/sqlite3/prepared_statement.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "detail/prepared_statement_handle.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__CYGWIN__) +#include + +// Workaround because cygwin gcc does not define to_string +namespace std +{ + template + std::string to_string(T t) + { + std::ostringstream stream; + + stream << t; + return stream.str(); + } +} // namespace std +#endif + +#ifdef SQLPP_DYNAMIC_LOADING +#include +#endif + +namespace sqlpp +{ + namespace sqlite3 + { +#ifdef SQLPP_DYNAMIC_LOADING + using namespace dynamic; +#endif + namespace + { + void check_bind_result(int result, const char* const type) + { + switch (result) + { + case SQLITE_OK: + return; + case SQLITE_RANGE: + throw sqlpp::exception("Sqlite3 error: " + std::string(type) + " bind value out of range"); + case SQLITE_NOMEM: + throw sqlpp::exception("Sqlite3 error: " + std::string(type) + " bind out of memory"); + case SQLITE_TOOBIG: + throw sqlpp::exception("Sqlite3 error: " + std::string(type) + " bind too big"); + default: + throw sqlpp::exception("Sqlite3 error: " + std::string(type) + + " bind returned unexpected value: " + std::to_string(result)); + } + } + } // namespace + + prepared_statement_t::prepared_statement_t(std::shared_ptr&& handle) + : _handle(std::move(handle)) + { + if (_handle and _handle->debug) + std::cerr << "Sqlite3 debug: Constructing prepared_statement, using handle at " << _handle.get() << std::endl; + } + + void prepared_statement_t::_reset() + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: resetting prepared statement" << std::endl; + sqlite3_reset(_handle->sqlite_statement); + } + + void prepared_statement_t::_bind_boolean_parameter(size_t index, const signed char* value, bool is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding boolean parameter " << (*value ? "true" : "false") + << " at index: " << index << ", being " << (is_null ? "" : "not ") << "null" << std::endl; + + int result; + if (not is_null) + result = sqlite3_bind_int(_handle->sqlite_statement, static_cast(index + 1), *value); + else + result = sqlite3_bind_null(_handle->sqlite_statement, static_cast(index + 1)); + check_bind_result(result, "boolean"); + } + + void prepared_statement_t::_bind_floating_point_parameter(size_t index, const double* value, bool is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding floating_point parameter " << *value << " at index: " << index + << ", being " << (is_null ? "" : "not ") << "null" << std::endl; + + int result; + if (not is_null) + { + if (std::isnan(*value)) + result = sqlite3_bind_text(_handle->sqlite_statement, static_cast(index + 1), "NaN", 3, SQLITE_STATIC); + else if (std::isinf(*value)) + { + if (*value > std::numeric_limits::max()) + result = sqlite3_bind_text(_handle->sqlite_statement, static_cast(index + 1), "Inf", 3, SQLITE_STATIC); + else + result = + sqlite3_bind_text(_handle->sqlite_statement, static_cast(index + 1), "-Inf", 4, SQLITE_STATIC); + } + else + result = sqlite3_bind_double(_handle->sqlite_statement, static_cast(index + 1), *value); + } + else + result = sqlite3_bind_null(_handle->sqlite_statement, static_cast(index + 1)); + check_bind_result(result, "floating_point"); + } + + void prepared_statement_t::_bind_integral_parameter(size_t index, const int64_t* value, bool is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding integral parameter " << *value << " at index: " << index << ", being " + << (is_null ? "" : "not ") << "null" << std::endl; + + int result; + if (not is_null) + result = sqlite3_bind_int64(_handle->sqlite_statement, static_cast(index + 1), *value); + else + result = sqlite3_bind_null(_handle->sqlite_statement, static_cast(index + 1)); + check_bind_result(result, "integral"); + } + + void prepared_statement_t::_bind_unsigned_integral_parameter(size_t index, const uint64_t* value, bool is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding unsigned integral parameter " << *value << " at index: " << index + << ", being " << (is_null ? "" : "not ") << "null" << std::endl; + + int result; + if (not is_null) + result = + sqlite3_bind_int64(_handle->sqlite_statement, static_cast(index + 1), static_cast(*value)); + else + result = sqlite3_bind_null(_handle->sqlite_statement, static_cast(index + 1)); + check_bind_result(result, "integral"); + } + + void prepared_statement_t::_bind_text_parameter(size_t index, const std::string* value, bool is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding text parameter " << *value << " at index: " << index << ", being " + << (is_null ? "" : "not ") << "null" << std::endl; + + int result; + if (not is_null) + result = sqlite3_bind_text(_handle->sqlite_statement, static_cast(index + 1), value->data(), + static_cast(value->size()), SQLITE_STATIC); + else + result = sqlite3_bind_null(_handle->sqlite_statement, static_cast(index + 1)); + check_bind_result(result, "text"); + } + + void prepared_statement_t::_bind_date_parameter(size_t index, const ::sqlpp::chrono::day_point* value, bool is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding date parameter " + << " at index: " << index << ", being " << (is_null ? "" : "not ") << "null" << std::endl; + + int result; + if (not is_null) + { + std::ostringstream os; + const auto ymd = ::date::year_month_day{*value}; + os << ymd; + const auto text = os.str(); + result = sqlite3_bind_text(_handle->sqlite_statement, static_cast(index + 1), text.data(), + static_cast(text.size()), SQLITE_TRANSIENT); + } + else + result = sqlite3_bind_null(_handle->sqlite_statement, static_cast(index + 1)); + check_bind_result(result, "date"); + } + + void prepared_statement_t::_bind_date_time_parameter(size_t index, + const ::sqlpp::chrono::microsecond_point* value, + bool is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding date_time parameter " + << " at index: " << index << ", being " << (is_null ? "" : "not ") << "null" << std::endl; + + int result; + if (not is_null) + { + const auto dp = ::sqlpp::chrono::floor<::date::days>(*value); + const auto time = date::make_time(::sqlpp::chrono::floor<::std::chrono::milliseconds>(*value - dp)); + const auto ymd = ::date::year_month_day{dp}; + std::ostringstream os; // gcc-4.9 does not support auto os = std::ostringstream{}; + os << ymd << ' ' << time; + const auto text = os.str(); + result = sqlite3_bind_text(_handle->sqlite_statement, static_cast(index + 1), text.data(), + static_cast(text.size()), SQLITE_TRANSIENT); + } + else + result = sqlite3_bind_null(_handle->sqlite_statement, static_cast(index + 1)); + check_bind_result(result, "date"); + } + void prepared_statement_t::_bind_blob_parameter(size_t index, const std::vector* value, bool is_null) + { + if (_handle->debug) + std::cerr << "Sqlite3 debug: binding vector parameter size of " << value->size() << " at index: " << index + << ", being " << (is_null ? "" : "not ") << "null" << std::endl; + + int result; + if (not is_null) + result = sqlite3_bind_blob(_handle->sqlite_statement, static_cast(index + 1), value->data(), + static_cast(value->size()), SQLITE_STATIC); + else + result = sqlite3_bind_null(_handle->sqlite_statement, static_cast(index + 1)); + check_bind_result(result, "blob"); + } + } // namespace sqlite3 +} // namespace sqlpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cdabd006..b5d74b47 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,15 +1,15 @@ -# Copyright (c) 2013-2016, Roland Bock +# Copyright (c) 2021-2021, Roland Bock # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # -# Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. # -# Redistributions in binary form must reproduce the above copyright notice, this -# list of conditions and the following disclaimer in the documentation and/or -# other materials provided with the distribution. +# 2. Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -21,59 +21,17 @@ # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +add_subdirectory(core/) -add_library(sqlpp11_testing INTERFACE) -target_include_directories(sqlpp11_testing INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - -if (NOT MSVC) -target_compile_options(sqlpp11_testing INTERFACE -Wall -Wextra -pedantic) -endif () - -set(test_names - BooleanExpression - CustomQuery - DateTime - Interpret - Insert - Remove - Update - Select - SelectType - Function - Prepared - Minimalistic - Result - Union - With - ) - -find_package(Boost 1.50) -if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) - list(APPEND test_names Ppgen) +if(MYSQL_CONNECTOR) + add_subdirectory(mysql) endif() - -create_test_sourcelist(test_sources test_main.cpp ${test_names}) -add_executable(sqlpp11_tests ${test_sources}) -target_link_libraries(sqlpp11_tests PRIVATE sqlpp11 sqlpp11_testing) -# conditionally bump to a higher C++ standard to test compatibility -if (SQLPP11_TESTS_CXX_STD) - set_property(TARGET sqlpp11_tests PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD}) - set_property(TARGET sqlpp11_tests PROPERTY CXX_STANDARD_REQUIRED yes) - set_property(TARGET sqlpp11_tests PROPERTY CXX_EXTENSIONS no) +if(POSTGRESQL_CONNECTOR) + add_subdirectory(postgresql) endif() -foreach(test IN LISTS test_names) - add_test(NAME sqlpp11.tests.${test} - COMMAND sqlpp11_tests ${test} - ) -endforeach() +if(SQLITE3_CONNECTOR OR SQLCIPHER_CONNECTOR) + add_subdirectory(sqlite3) +endif() -# if you want to use the generator, you can do something like this: -#find_package(PythonInterp REQUIRED) -#add_custom_command( -# OUTPUT "${CMAKE_CURRENT_LIST_DIR}/Sample.h" -# COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/scripts/ddl2cpp" "${CMAKE_CURRENT_LIST_DIR}/sample.sql" Sample test -# DEPENDS "${CMAKE_CURRENT_LIST_DIR}/sample.sql" -# VERBATIM) diff --git a/tests/core/CMakeLists.txt b/tests/core/CMakeLists.txt new file mode 100644 index 00000000..df5acca7 --- /dev/null +++ b/tests/core/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) 2021-2021, Roland Bock +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +add_subdirectory(usage) +add_subdirectory(serialize) +add_subdirectory(constraints) +add_subdirectory(static_asserts) + + diff --git a/test_constraints/CMakeLists.txt b/tests/core/constraints/CMakeLists.txt similarity index 100% rename from test_constraints/CMakeLists.txt rename to tests/core/constraints/CMakeLists.txt diff --git a/test_constraints/count_of_count.cpp b/tests/core/constraints/count_of_count.cpp similarity index 100% rename from test_constraints/count_of_count.cpp rename to tests/core/constraints/count_of_count.cpp diff --git a/test_constraints/max_of_max.cpp b/tests/core/constraints/max_of_max.cpp similarity index 100% rename from test_constraints/max_of_max.cpp rename to tests/core/constraints/max_of_max.cpp diff --git a/test_constraints/must_not_insert.cpp b/tests/core/constraints/must_not_insert.cpp similarity index 100% rename from test_constraints/must_not_insert.cpp rename to tests/core/constraints/must_not_insert.cpp diff --git a/test_constraints/must_not_update.cpp b/tests/core/constraints/must_not_update.cpp similarity index 100% rename from test_constraints/must_not_update.cpp rename to tests/core/constraints/must_not_update.cpp diff --git a/test_constraints/require_insert.cpp b/tests/core/constraints/require_insert.cpp similarity index 100% rename from test_constraints/require_insert.cpp rename to tests/core/constraints/require_insert.cpp diff --git a/test_serializer/As.cpp b/tests/core/serialize/As.cpp similarity index 100% rename from test_serializer/As.cpp rename to tests/core/serialize/As.cpp diff --git a/test_serializer/Blob.cpp b/tests/core/serialize/Blob.cpp similarity index 100% rename from test_serializer/Blob.cpp rename to tests/core/serialize/Blob.cpp diff --git a/test_serializer/CMakeLists.txt b/tests/core/serialize/CMakeLists.txt similarity index 100% rename from test_serializer/CMakeLists.txt rename to tests/core/serialize/CMakeLists.txt diff --git a/test_serializer/CustomQuery.cpp b/tests/core/serialize/CustomQuery.cpp similarity index 100% rename from test_serializer/CustomQuery.cpp rename to tests/core/serialize/CustomQuery.cpp diff --git a/test_serializer/DynamicWhere.cpp b/tests/core/serialize/DynamicWhere.cpp similarity index 100% rename from test_serializer/DynamicWhere.cpp rename to tests/core/serialize/DynamicWhere.cpp diff --git a/test_serializer/ForUpdate.cpp b/tests/core/serialize/ForUpdate.cpp similarity index 100% rename from test_serializer/ForUpdate.cpp rename to tests/core/serialize/ForUpdate.cpp diff --git a/test_serializer/From.cpp b/tests/core/serialize/From.cpp similarity index 100% rename from test_serializer/From.cpp rename to tests/core/serialize/From.cpp diff --git a/test_serializer/In.cpp b/tests/core/serialize/In.cpp similarity index 100% rename from test_serializer/In.cpp rename to tests/core/serialize/In.cpp diff --git a/test_serializer/Insert.cpp b/tests/core/serialize/Insert.cpp similarity index 100% rename from test_serializer/Insert.cpp rename to tests/core/serialize/Insert.cpp diff --git a/test_serializer/Over.cpp b/tests/core/serialize/Over.cpp similarity index 100% rename from test_serializer/Over.cpp rename to tests/core/serialize/Over.cpp diff --git a/test_serializer/ParameterizedVerbatim.cpp b/tests/core/serialize/ParameterizedVerbatim.cpp similarity index 100% rename from test_serializer/ParameterizedVerbatim.cpp rename to tests/core/serialize/ParameterizedVerbatim.cpp diff --git a/test_serializer/TableAlias.cpp b/tests/core/serialize/TableAlias.cpp similarity index 100% rename from test_serializer/TableAlias.cpp rename to tests/core/serialize/TableAlias.cpp diff --git a/test_serializer/Where.cpp b/tests/core/serialize/Where.cpp similarity index 100% rename from test_serializer/Where.cpp rename to tests/core/serialize/Where.cpp diff --git a/test_serializer/compare.h b/tests/core/serialize/compare.h similarity index 100% rename from test_serializer/compare.h rename to tests/core/serialize/compare.h diff --git a/test_static_asserts/AssertTables.h b/tests/core/static_asserts/AssertTables.h similarity index 100% rename from test_static_asserts/AssertTables.h rename to tests/core/static_asserts/AssertTables.h diff --git a/test_static_asserts/AssertTables.sql b/tests/core/static_asserts/AssertTables.sql similarity index 100% rename from test_static_asserts/AssertTables.sql rename to tests/core/static_asserts/AssertTables.sql diff --git a/test_static_asserts/CMakeLists.txt b/tests/core/static_asserts/CMakeLists.txt similarity index 100% rename from test_static_asserts/CMakeLists.txt rename to tests/core/static_asserts/CMakeLists.txt diff --git a/test_static_asserts/aggregates.cpp b/tests/core/static_asserts/aggregates.cpp similarity index 100% rename from test_static_asserts/aggregates.cpp rename to tests/core/static_asserts/aggregates.cpp diff --git a/test_static_asserts/case.cpp b/tests/core/static_asserts/case.cpp similarity index 100% rename from test_static_asserts/case.cpp rename to tests/core/static_asserts/case.cpp diff --git a/test_static_asserts/date.cpp b/tests/core/static_asserts/date.cpp similarity index 100% rename from test_static_asserts/date.cpp rename to tests/core/static_asserts/date.cpp diff --git a/test_static_asserts/date_time.cpp b/tests/core/static_asserts/date_time.cpp similarity index 100% rename from test_static_asserts/date_time.cpp rename to tests/core/static_asserts/date_time.cpp diff --git a/test_static_asserts/from.cpp b/tests/core/static_asserts/from.cpp similarity index 100% rename from test_static_asserts/from.cpp rename to tests/core/static_asserts/from.cpp diff --git a/test_static_asserts/having.cpp b/tests/core/static_asserts/having.cpp similarity index 100% rename from test_static_asserts/having.cpp rename to tests/core/static_asserts/having.cpp diff --git a/test_static_asserts/in.cpp b/tests/core/static_asserts/in.cpp similarity index 100% rename from test_static_asserts/in.cpp rename to tests/core/static_asserts/in.cpp diff --git a/test_static_asserts/insert.cpp b/tests/core/static_asserts/insert.cpp similarity index 100% rename from test_static_asserts/insert.cpp rename to tests/core/static_asserts/insert.cpp diff --git a/test_static_asserts/join.cpp b/tests/core/static_asserts/join.cpp similarity index 100% rename from test_static_asserts/join.cpp rename to tests/core/static_asserts/join.cpp diff --git a/test_static_asserts/no_self_compare.cpp b/tests/core/static_asserts/no_self_compare.cpp similarity index 100% rename from test_static_asserts/no_self_compare.cpp rename to tests/core/static_asserts/no_self_compare.cpp diff --git a/test_static_asserts/text.cpp b/tests/core/static_asserts/text.cpp similarity index 100% rename from test_static_asserts/text.cpp rename to tests/core/static_asserts/text.cpp diff --git a/test_static_asserts/unwrapped_bool.cpp b/tests/core/static_asserts/unwrapped_bool.cpp similarity index 100% rename from test_static_asserts/unwrapped_bool.cpp rename to tests/core/static_asserts/unwrapped_bool.cpp diff --git a/test_static_asserts/update_list.cpp b/tests/core/static_asserts/update_list.cpp similarity index 100% rename from test_static_asserts/update_list.cpp rename to tests/core/static_asserts/update_list.cpp diff --git a/test_static_asserts/where.cpp b/tests/core/static_asserts/where.cpp similarity index 100% rename from test_static_asserts/where.cpp rename to tests/core/static_asserts/where.cpp diff --git a/tests/BooleanExpression.cpp b/tests/core/usage/BooleanExpression.cpp similarity index 100% rename from tests/BooleanExpression.cpp rename to tests/core/usage/BooleanExpression.cpp diff --git a/tests/core/usage/CMakeLists.txt b/tests/core/usage/CMakeLists.txt new file mode 100644 index 00000000..cdabd006 --- /dev/null +++ b/tests/core/usage/CMakeLists.txt @@ -0,0 +1,79 @@ +# Copyright (c) 2013-2016, Roland Bock +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +add_library(sqlpp11_testing INTERFACE) +target_include_directories(sqlpp11_testing INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) + +if (NOT MSVC) +target_compile_options(sqlpp11_testing INTERFACE -Wall -Wextra -pedantic) +endif () + +set(test_names + BooleanExpression + CustomQuery + DateTime + Interpret + Insert + Remove + Update + Select + SelectType + Function + Prepared + Minimalistic + Result + Union + With + ) + +find_package(Boost 1.50) +if(Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) + list(APPEND test_names Ppgen) +endif() + + +create_test_sourcelist(test_sources test_main.cpp ${test_names}) +add_executable(sqlpp11_tests ${test_sources}) +target_link_libraries(sqlpp11_tests PRIVATE sqlpp11 sqlpp11_testing) +# conditionally bump to a higher C++ standard to test compatibility +if (SQLPP11_TESTS_CXX_STD) + set_property(TARGET sqlpp11_tests PROPERTY CXX_STANDARD ${SQLPP11_TESTS_CXX_STD}) + set_property(TARGET sqlpp11_tests PROPERTY CXX_STANDARD_REQUIRED yes) + set_property(TARGET sqlpp11_tests PROPERTY CXX_EXTENSIONS no) +endif() + +foreach(test IN LISTS test_names) + add_test(NAME sqlpp11.tests.${test} + COMMAND sqlpp11_tests ${test} + ) +endforeach() + +# if you want to use the generator, you can do something like this: +#find_package(PythonInterp REQUIRED) +#add_custom_command( +# OUTPUT "${CMAKE_CURRENT_LIST_DIR}/Sample.h" +# COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/scripts/ddl2cpp" "${CMAKE_CURRENT_LIST_DIR}/sample.sql" Sample test +# DEPENDS "${CMAKE_CURRENT_LIST_DIR}/sample.sql" +# VERBATIM) diff --git a/tests/CustomQuery.cpp b/tests/core/usage/CustomQuery.cpp similarity index 100% rename from tests/CustomQuery.cpp rename to tests/core/usage/CustomQuery.cpp diff --git a/tests/DateTime.cpp b/tests/core/usage/DateTime.cpp similarity index 100% rename from tests/DateTime.cpp rename to tests/core/usage/DateTime.cpp diff --git a/tests/Function.cpp b/tests/core/usage/Function.cpp similarity index 100% rename from tests/Function.cpp rename to tests/core/usage/Function.cpp diff --git a/tests/Insert.cpp b/tests/core/usage/Insert.cpp similarity index 100% rename from tests/Insert.cpp rename to tests/core/usage/Insert.cpp diff --git a/tests/Interpret.cpp b/tests/core/usage/Interpret.cpp similarity index 100% rename from tests/Interpret.cpp rename to tests/core/usage/Interpret.cpp diff --git a/tests/Minimalistic.cpp b/tests/core/usage/Minimalistic.cpp similarity index 100% rename from tests/Minimalistic.cpp rename to tests/core/usage/Minimalistic.cpp diff --git a/tests/MockDb.h b/tests/core/usage/MockDb.h similarity index 100% rename from tests/MockDb.h rename to tests/core/usage/MockDb.h diff --git a/tests/Ppgen.cpp b/tests/core/usage/Ppgen.cpp similarity index 100% rename from tests/Ppgen.cpp rename to tests/core/usage/Ppgen.cpp diff --git a/tests/Prepared.cpp b/tests/core/usage/Prepared.cpp similarity index 100% rename from tests/Prepared.cpp rename to tests/core/usage/Prepared.cpp diff --git a/tests/Remove.cpp b/tests/core/usage/Remove.cpp similarity index 100% rename from tests/Remove.cpp rename to tests/core/usage/Remove.cpp diff --git a/tests/Result.cpp b/tests/core/usage/Result.cpp similarity index 100% rename from tests/Result.cpp rename to tests/core/usage/Result.cpp diff --git a/tests/Sample.h b/tests/core/usage/Sample.h similarity index 100% rename from tests/Sample.h rename to tests/core/usage/Sample.h diff --git a/tests/Select.cpp b/tests/core/usage/Select.cpp similarity index 100% rename from tests/Select.cpp rename to tests/core/usage/Select.cpp diff --git a/tests/SelectType.cpp b/tests/core/usage/SelectType.cpp similarity index 100% rename from tests/SelectType.cpp rename to tests/core/usage/SelectType.cpp diff --git a/tests/Union.cpp b/tests/core/usage/Union.cpp similarity index 100% rename from tests/Union.cpp rename to tests/core/usage/Union.cpp diff --git a/tests/Update.cpp b/tests/core/usage/Update.cpp similarity index 100% rename from tests/Update.cpp rename to tests/core/usage/Update.cpp diff --git a/tests/With.cpp b/tests/core/usage/With.cpp similarity index 100% rename from tests/With.cpp rename to tests/core/usage/With.cpp diff --git a/tests/is_regular.h b/tests/core/usage/is_regular.h similarity index 100% rename from tests/is_regular.h rename to tests/core/usage/is_regular.h diff --git a/tests/sample.sql b/tests/core/usage/sample.sql similarity index 100% rename from tests/sample.sql rename to tests/core/usage/sample.sql diff --git a/tests/sqlite3/CMakeLists.txt b/tests/sqlite3/CMakeLists.txt new file mode 100644 index 00000000..dca5a095 --- /dev/null +++ b/tests/sqlite3/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright (c) 2021-2021, Roland Bock +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +add_subdirectory(usage) + + diff --git a/tests/sqlite3/usage/AttachTest.cpp b/tests/sqlite3/usage/AttachTest.cpp new file mode 100644 index 00000000..92e19570 --- /dev/null +++ b/tests/sqlite3/usage/AttachTest.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TabSample.h" +#include +#include +#include + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include +#include + +namespace sql = sqlpp::sqlite3; + +int main() +{ + sql::connection_config config; + config.path_to_database = ":memory:"; + config.flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + config.debug = true; + + // Opening a connection to an in-memory database and creating a table in it + sql::connection db(config); + db.execute(R"(CREATE TABLE tab_sample ( + alpha INTEGER PRIMARY KEY, + beta varchar(255) DEFAULT NULL, + gamma bool DEFAULT NULL + ))"); + + // Attaching another in-memory database and creating the same table in it + auto other = db.attach(config, "other"); + db.execute(R"(CREATE TABLE other.tab_sample ( + alpha INTEGER PRIMARY KEY, + beta varchar(255) DEFAULT NULL, + gamma bool DEFAULT NULL + ))"); + + auto left = TabSample{}; + auto right = + schema_qualified_table(other, TabSample{}).as(sqlpp::alias::right); // this is a table in the attached database + + // inserting in one tab_sample + db(insert_into(left).default_values()); + + // selecting from the other tab_sample + assert(db(select(all_of(right)).from(right).unconditionally()).empty()); + + return 0; +} diff --git a/tests/sqlite3/usage/AutoIncrementTest.cpp b/tests/sqlite3/usage/AutoIncrementTest.cpp new file mode 100644 index 00000000..ea3fe2f1 --- /dev/null +++ b/tests/sqlite3/usage/AutoIncrementTest.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TabSample.h" +#include +#include +#include + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include +#include +#include + +namespace sql = sqlpp::sqlite3; +int main() +{ + sql::connection_config config; + config.path_to_database = ":memory:"; + config.flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + config.debug = true; + + sql::connection db(config); + db.execute(R"(CREATE TABLE tab_sample ( + alpha INTEGER PRIMARY KEY AUTOINCREMENT, + beta bool DEFAULT NULL, + gamma varchar(255) DEFAULT NULL + ))"); + + const auto tab = TabSample{}; + db(insert_into(tab).default_values()); + db(insert_into(tab).default_values()); + db(insert_into(tab).default_values()); + + std::set results; + for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) + { + results.insert(row.alpha); + }; + const auto expected = std::set{1, 2, 3}; + assert(results == expected); + + return 0; +} diff --git a/tests/sqlite3/usage/BlobSample.h b/tests/sqlite3/usage/BlobSample.h new file mode 100644 index 00000000..25cce282 --- /dev/null +++ b/tests/sqlite3/usage/BlobSample.h @@ -0,0 +1,78 @@ +// generated by ../../sqlpp11/scripts/ddl2cpp -fail-on-parse BlobSample.sql BlobSample blob +#ifndef BLOB_BLOBSAMPLE_H +#define BLOB_BLOBSAMPLE_H + +#include +#include +#include + +namespace BlobSample_ +{ + struct Id + { + struct _alias_t + { + static constexpr const char _literal[] = "id"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T id; + T& operator()() + { + return id; + } + const T& operator()() const + { + return id; + } + }; + }; + using _traits = sqlpp::make_traits; + }; + struct Data + { + struct _alias_t + { + static constexpr const char _literal[] = "data"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T data; + T& operator()() + { + return data; + } + const T& operator()() const + { + return data; + } + }; + }; + using _traits = sqlpp::make_traits; + }; +} // namespace BlobSample_ + +struct BlobSample : sqlpp::table_t +{ + struct _alias_t + { + static constexpr const char _literal[] = "blob_sample"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T blobSample; + T& operator()() + { + return blobSample; + } + const T& operator()() const + { + return blobSample; + } + }; + }; +}; +#endif diff --git a/tests/sqlite3/usage/BlobSample.sql b/tests/sqlite3/usage/BlobSample.sql new file mode 100644 index 00000000..cc9311e0 --- /dev/null +++ b/tests/sqlite3/usage/BlobSample.sql @@ -0,0 +1,4 @@ +CREATE TABLE blob_sample ( + id INTEGER PRIMARY KEY, + data blob +) ENGINE=InnoDB DEFAULT CHARSET=latin1; diff --git a/tests/sqlite3/usage/BlobTest.cpp b/tests/sqlite3/usage/BlobTest.cpp new file mode 100644 index 00000000..8b0c657a --- /dev/null +++ b/tests/sqlite3/usage/BlobTest.cpp @@ -0,0 +1,102 @@ +#include "BlobSample.h" +#include +#include + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include +#include +#include + +namespace sql = sqlpp::sqlite3; +const auto blob = BlobSample{}; + +/* + * max default blob/text is 1,000,000,000 + * But 999,999,993 is the biggest one SQLITE will accept + * without throwing SQLITE_TOOBIG + * But it takes too long (over 5s) to generate and check + */ +constexpr size_t blob_size = 1000 * 1000ul; +constexpr size_t blob_small_size = 999; + +void verify_blob(sql::connection& db, const std::vector& data, uint64_t id) +{ + auto result = db(select(blob.data).from(blob).where(blob.id == id)); + const auto& result_row = result.front(); + std::cerr << "Insert size: " << data.size() << std::endl; + std::cerr << "Select size: " << result_row.data.len << std::endl; + if (data.size() != result_row.data.len) + { + std::cerr << "Size mismatch" << std::endl; + + throw std::runtime_error("Size mismatch " + std::to_string(data.size()) + + " != " + std::to_string(result_row.data.len)); + } + std::cerr << "Verifying content" << std::endl; + std::vector result_blob(result_row.data.blob, result_row.data.blob + result_row.data.len); + if (data != result_blob) + { + std::cout << "Content mismatch ([row] original -> received)" << std::endl; + + for (size_t i = 0; i < data.size(); i++) + { + if (data[i] != result_row.data.blob[i]) + { + std::cerr << "[" << i << "] " << static_cast(data.at(i)) << " -> " << static_cast(result_blob.at(i)) + << std::endl; + } + } + throw std::runtime_error("Content mismatch"); + } +} + +int main() +{ + sql::connection_config config; + config.path_to_database = ":memory:"; + config.flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + config.debug = true; + + sql::connection db(config); + db.execute(R"(CREATE TABLE blob_sample ( + id INTEGER PRIMARY KEY, + data blob + ))"); + std::cerr << "Generating data " << blob_size << std::endl; + std::vector data(blob_size); + std::uniform_int_distribution distribution(0, 255); + std::mt19937 engine; + auto generator = std::bind(distribution, engine); + std::generate_n(data.begin(), blob_size, generator); + + std::vector data_smaller(blob_small_size); + std::generate_n(data_smaller.begin(), blob_small_size, generator); + + // If we use the bigger blob it will trigger SQLITE_TOOBIG for the query + auto id = db(insert_into(blob).set(blob.data = data_smaller)); + + auto prepared_insert = db.prepare(insert_into(blob).set(blob.data = parameter(blob.data))); + prepared_insert.params.data = data; + auto prep_id = db(prepared_insert); + prepared_insert.params.data.set_null(); + auto null_id = db(prepared_insert); + + verify_blob(db, data_smaller, id); + verify_blob(db, data, prep_id); + { + auto result = db(select(blob.data).from(blob).where(blob.id == null_id)); + const auto& result_row = result.front(); + std::cerr << "Null blob is_null:\t" << std::boolalpha << result_row.data.is_null() << std::endl; + std::cerr << "Null blob len == 0:\t" << std::boolalpha << (result_row.data.len == 0) << std::endl; + std::cerr << "Null blob blob == nullptr:\t" << std::boolalpha << (result_row.data.blob == nullptr) << std::endl; + if (!result_row.data.is_null() || result_row.data.len != 0 || result_row.data.blob != nullptr) + { + throw std::runtime_error("Null blob has incorrect values"); + } + } + return 0; +} diff --git a/tests/sqlite3/usage/CMakeLists.txt b/tests/sqlite3/usage/CMakeLists.txt new file mode 100644 index 00000000..63264be1 --- /dev/null +++ b/tests/sqlite3/usage/CMakeLists.txt @@ -0,0 +1,60 @@ +# Copyright (c) 2013 - 2016, Roland Bock +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) + +macro (build_and_run arg) + # Add headers to sources to enable file browsing in IDEs + add_executable(Sqlpp11Sqlite3${arg} ${arg}.cpp) + + target_link_libraries(Sqlpp11Sqlite3${arg} PRIVATE sqlpp11-connector-sqlite3) + if (NOT MSVC) + target_compile_options(Sqlpp11Sqlite3${arg} INTERFACE -Wall -Wextra -pedantic) + endif () + add_test(NAME Sqlpp11Sqlite3${arg} COMMAND Sqlpp11Sqlite3${arg}) +endmacro () + +build_and_run(DateTimeTest) +build_and_run(SampleTest) +build_and_run(SelectTest) +build_and_run(UnionTest) +build_and_run(WithTest) +build_and_run(AttachTest) +build_and_run(DynamicSelectTest) +build_and_run(AutoIncrementTest) +build_and_run(TransactionTest) +build_and_run(FloatingPointTest) +build_and_run(IntegralTest) +build_and_run(BlobTest) + +# the dynamic loading test needs the extra option "SQLPP_DYNAMIC_LOADING" and does NOT link the sqlite libs +if (SQLPP_DYNAMIC_LOADING) + add_executable(Sqlpp11Sqlite3DynamicLoadingTest "DynamicLoadingTest.cpp" ${sqlpp_headers}) + target_link_libraries(Sqlpp11Sqlite3DynamicLoadingTest sqlpp11-connector-sqlite3-dynamic) + if (NOT MSVC) + target_link_libraries(Sqlpp11Sqlite3DynamicLoadingTest dl) + target_compile_options(Sqlpp11Sqlite3DynamicLoadingTest INTERFACE -Wall -Wextra -pedantic) + endif () + add_test(NAME Sqlpp11Sqlite3DynamicLoadingTest COMMAND Sqlpp11Sqlite3DynamicLoadingTest) +endif() diff --git a/tests/sqlite3/usage/DateTimeTest.cpp b/tests/sqlite3/usage/DateTimeTest.cpp new file mode 100644 index 00000000..3f99c8be --- /dev/null +++ b/tests/sqlite3/usage/DateTimeTest.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TabSample.h" +#include +#include +#include + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include +#include +#include + +namespace +{ + const auto now = ::sqlpp::chrono::floor<::std::chrono::milliseconds>(std::chrono::system_clock::now()); + const auto today = ::sqlpp::chrono::floor<::sqlpp::chrono::days>(now); + const auto yesterday = today - ::sqlpp::chrono::days{1}; + + template + auto require_equal(int line, const L& l, const R& r) -> void + { + if (l != r) + { + std::cerr << line << ": "; + serialize(::sqlpp::wrap_operand_t{l}, std::cerr); + std::cerr << " != "; + serialize(::sqlpp::wrap_operand_t{r}, std::cerr); + throw std::runtime_error("Unexpected result"); + } + } +} // namespace + +namespace sql = sqlpp::sqlite3; +int main() +{ + try + { + sql::connection_config config; + config.path_to_database = ":memory:"; + config.flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + config.debug = true; + + sql::connection db(config); + db.execute(R"(CREATE TABLE tab_date_time ( + col_day_point DATE, + col_time_point DATETIME + ))"); + + const auto tab = TabDateTime{}; + db(insert_into(tab).default_values()); + + for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) + { + require_equal(__LINE__, row.colDayPoint.is_null(), true); + require_equal(__LINE__, row.colDayPoint.value(), ::sqlpp::chrono::day_point{}); + require_equal(__LINE__, row.colTimePoint.is_null(), true); + require_equal(__LINE__, row.colTimePoint.value(), ::sqlpp::chrono::microsecond_point{}); + } + + db(update(tab).set(tab.colDayPoint = today, tab.colTimePoint = now).unconditionally()); + + for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) + { + require_equal(__LINE__, row.colDayPoint.value(), today); + require_equal(__LINE__, row.colTimePoint.value(), now); + } + + db(update(tab).set(tab.colDayPoint = yesterday, tab.colTimePoint = today).unconditionally()); + + for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) + { + require_equal(__LINE__, row.colDayPoint.value(), yesterday); + require_equal(__LINE__, row.colTimePoint.value(), today); + } + + auto prepared_update = db.prepare( + update(tab) + .set(tab.colDayPoint = parameter(tab.colDayPoint), tab.colTimePoint = parameter(tab.colTimePoint)) + .unconditionally()); + prepared_update.params.colDayPoint = today; + prepared_update.params.colTimePoint = now; + std::cout << "---- running prepared update ----" << std::endl; + db(prepared_update); + std::cout << "---- finished prepared update ----" << std::endl; + for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) + { + require_equal(__LINE__, row.colDayPoint.value(), today); + require_equal(__LINE__, row.colTimePoint.value(), now); + } + } + catch (const std::exception& e) + { + std::cerr << "Exception: " << e.what() << std::endl; + return 1; + } + catch (...) + { + std::cerr << "Unknown exception: " << std::endl; + return 1; + } + + return 0; +} diff --git a/tests/sqlite3/usage/DynamicLoadingTest.cpp b/tests/sqlite3/usage/DynamicLoadingTest.cpp new file mode 100644 index 00000000..7677a7f9 --- /dev/null +++ b/tests/sqlite3/usage/DynamicLoadingTest.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TabSample.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include +#include + +#include + +SQLPP_ALIAS_PROVIDER(left) + +namespace sql = sqlpp::sqlite3; +int main() +{ + sql::connection_config config; + config.path_to_database = ":memory:"; + config.flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + config.debug = true; + + sql::connection db(config); + db.execute("CREATE TABLE tab_sample (\ + alpha bigint(20) DEFAULT NULL,\ + beta varchar(255) DEFAULT NULL,\ + gamma bool DEFAULT NULL\ + )"); + + const auto tab = TabSample{}; + + auto i = insert_into(tab).columns(tab.beta, tab.gamma); + i.values.add(tab.beta = "rhabarbertorte", tab.gamma = false); + // i.values.add(tab.beta = "cheesecake", tab.gamma = false) + // i.values.add(tab.beta = "kaesekuchen", tab.gamma = true) + auto last_insert_rowid = db(i); + + std::cerr << "last insert rowid: " << last_insert_rowid << std::endl; + + // Just to demonstrate that you can call basically any function + std::cerr << "last insert rowid: " + << db(select(sqlpp::verbatim("last_insert_rowid()").as(tab.alpha))).front().alpha + << std::endl; + + // select a static (alpha) and a dynamic column (beta) + auto s = dynamic_select(db).dynamic_columns(tab.alpha.as(left)).from(tab).unconditionally(); + s.selected_columns.add(tab.beta); + s.selected_columns.add(tab.gamma); + for (const auto& row : db(s)) + { + std::cerr << "row.alpha: " << row.left << ", row.beta: " << row.at("beta") << ", row.gamma: " << row.at("gamma") + << std::endl; + }; + return 0; +} diff --git a/tests/sqlite3/usage/DynamicSelectTest.cpp b/tests/sqlite3/usage/DynamicSelectTest.cpp new file mode 100644 index 00000000..b8bc5ee3 --- /dev/null +++ b/tests/sqlite3/usage/DynamicSelectTest.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TabSample.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include +#include + +SQLPP_ALIAS_PROVIDER(left) + +namespace sql = sqlpp::sqlite3; +int main() +{ + sql::connection_config config; + config.path_to_database = ":memory:"; + config.flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + config.debug = true; + + sql::connection db(config); + db.execute("CREATE TABLE tab_sample (\ + alpha bigint(20) DEFAULT NULL,\ + beta varchar(255) DEFAULT NULL,\ + gamma bool DEFAULT NULL\ + )"); + + const auto tab = TabSample{}; + + auto i = insert_into(tab).columns(tab.beta, tab.gamma); + i.values.add(tab.beta = "rhabarbertorte", tab.gamma = false); + // i.values.add(tab.beta = "cheesecake", tab.gamma = false) + // i.values.add(tab.beta = "kaesekuchen", tab.gamma = true) + auto last_insert_rowid = db(i); + + std::cerr << "last insert rowid: " << last_insert_rowid << std::endl; + + // Just to demonstrate that you can call basically any function + std::cerr << "last insert rowid: " + << db(select(sqlpp::verbatim("last_insert_rowid()").as(tab.alpha))).front().alpha + << std::endl; + + // select a static (alpha) and a dynamic column (beta) + auto s = dynamic_select(db).dynamic_columns(tab.alpha.as(left)).from(tab).unconditionally(); + s.selected_columns.add(tab.beta); + s.selected_columns.add(tab.gamma); + for (const auto& row : db(s)) + { + std::cerr << "row.alpha: " << row.left << ", row.beta: " << row.at("beta") << ", row.gamma: " << row.at("gamma") + << std::endl; + }; + return 0; +} diff --git a/tests/sqlite3/usage/FloatingPointTest.cpp b/tests/sqlite3/usage/FloatingPointTest.cpp new file mode 100644 index 00000000..fe668c3e --- /dev/null +++ b/tests/sqlite3/usage/FloatingPointTest.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "FpSample.h" +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include +#include + +namespace sql = sqlpp::sqlite3; + +const auto fp = FpSample{}; + +template +auto require_equal(int line, const L& l, const R& r) -> void +{ + if (l != r) + { + std::cerr << line << ": "; + serialize(::sqlpp::wrap_operand_t{l}, std::cerr); + std::cerr << " != "; + serialize(::sqlpp::wrap_operand_t{r}, std::cerr); + throw std::runtime_error("Unexpected result"); + } +} + +static auto require(int line, bool condition) -> void +{ + if (!condition) + { + std::cerr << line << " condition violated"; + throw std::runtime_error("Unexpected result"); + } +} + +int main() +{ + sql::connection_config config; + config.path_to_database = ":memory:"; + config.flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + config.debug = true; + + sql::connection db(config); + db.execute(R"(CREATE TABLE fp_sample ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + fp REAL + ))"); + + db.execute("INSERT into fp_sample (id, fp) values(NULL, 1.0)"); + db.execute("INSERT into fp_sample (id, fp) values(NULL, 'Inf')"); + db.execute("INSERT into fp_sample (id, fp) values(NULL, 'Nan')"); + db.execute("INSERT into fp_sample (id, fp) values(NULL, 'SomeString')"); + db(insert_into(fp).set(fp.fp = std::numeric_limits::quiet_NaN())); + db(insert_into(fp).set(fp.fp = std::numeric_limits::infinity())); + db(insert_into(fp).set(fp.fp = -std::numeric_limits::infinity())); + + auto prepared_insert = db.prepare(insert_into(fp).set(fp.fp = parameter(fp.fp))); + prepared_insert.params.fp = std::numeric_limits::quiet_NaN(); + db(prepared_insert); + prepared_insert.params.fp = std::numeric_limits::infinity(); + db(prepared_insert); + prepared_insert.params.fp = -std::numeric_limits::infinity(); + db(prepared_insert); + + auto q = select(fp.fp).from(fp).unconditionally(); + auto rows = db(q); + + // raw string inserts + require_equal(__LINE__, rows.front().fp, 1.0); + rows.pop_front(); + require(__LINE__, std::isinf(rows.front().fp.value())); + rows.pop_front(); + require(__LINE__, std::isnan(rows.front().fp.value())); + rows.pop_front(); + require_equal(__LINE__, rows.front().fp, 0.0); + rows.pop_front(); + + // dsl inserts + require(__LINE__, std::isnan(rows.front().fp.value())); + rows.pop_front(); + require(__LINE__, std::isinf(rows.front().fp.value())); + require(__LINE__, rows.front().fp.value() > std::numeric_limits::max()); + rows.pop_front(); + require(__LINE__, std::isinf(rows.front().fp.value())); + require(__LINE__, rows.front().fp.value() < std::numeric_limits::lowest()); + + // prepared dsl inserts + rows.pop_front(); + require(__LINE__, std::isnan(rows.front().fp.value())); + rows.pop_front(); + require(__LINE__, std::isinf(rows.front().fp.value())); + require(__LINE__, rows.front().fp.value() > std::numeric_limits::max()); + rows.pop_front(); + require(__LINE__, std::isinf(rows.front().fp.value())); + require(__LINE__, rows.front().fp.value() < std::numeric_limits::lowest()); + + return 0; +} diff --git a/tests/sqlite3/usage/FpSample.h b/tests/sqlite3/usage/FpSample.h new file mode 100644 index 00000000..8c841f03 --- /dev/null +++ b/tests/sqlite3/usage/FpSample.h @@ -0,0 +1,79 @@ +// generated by ../../sqlpp11/scripts/ddl2cpp -fail-on-parse FpSample.sql FpSample fp +#ifndef FP_FPSAMPLE_H +#define FP_FPSAMPLE_H + +#include +#include +#include + +namespace FpSample_ +{ + struct Id + { + struct _alias_t + { + static constexpr const char _literal[] = "id"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T id; + T& operator()() + { + return id; + } + const T& operator()() const + { + return id; + } + }; + }; + using _traits = sqlpp::make_traits; + }; + struct Fp + { + struct _alias_t + { + static constexpr const char _literal[] = "fp"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T fp; + T& operator()() + { + return fp; + } + const T& operator()() const + { + return fp; + } + }; + }; + using _traits = sqlpp::make_traits; + }; +} + +struct FpSample : sqlpp::table_t +{ + struct _alias_t + { + static constexpr const char _literal[] = "fp_sample"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T fpSample; + T& operator()() + { + return fpSample; + } + const T& operator()() const + { + return fpSample; + } + }; + }; +}; + +#endif diff --git a/tests/sqlite3/usage/FpSample.sql b/tests/sqlite3/usage/FpSample.sql new file mode 100644 index 00000000..48fb9257 --- /dev/null +++ b/tests/sqlite3/usage/FpSample.sql @@ -0,0 +1,4 @@ +CREATE TABLE fp_sample ( + id INTEGER PRIMARY KEY, + fp DOUBLE +) ENGINE=InnoDB DEFAULT CHARSET=latin1; diff --git a/tests/sqlite3/usage/IntegralSample.h b/tests/sqlite3/usage/IntegralSample.h new file mode 100644 index 00000000..75c3fee5 --- /dev/null +++ b/tests/sqlite3/usage/IntegralSample.h @@ -0,0 +1,79 @@ +#ifndef INTEGRAL_SAMPLE_H +#define INTEGRAL_SAMPLE_H + +#include +#include +#include + +namespace IntegralSample_ +{ + struct SignedValue + { + struct _alias_t + { + static constexpr const char _literal[] = "signed_value"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T signedValue; + T& operator()() + { + return signedValue; + } + const T& operator()() const + { + return signedValue; + } + }; + }; + using _traits = sqlpp::make_traits; + }; + struct UnsignedValue + { + struct _alias_t + { + static constexpr const char _literal[] = "unsigned_value"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T unsignedValue; + T& operator()() + { + return unsignedValue; + } + const T& operator()() const + { + return unsignedValue; + } + }; + }; + using _traits = sqlpp::make_traits; + }; + +} // namespace IntegralSample_ + +struct IntegralSample : sqlpp::table_t +{ + struct _alias_t + { + static constexpr const char _literal[] = "integral_sample"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T fpSample; + T& operator()() + { + return fpSample; + } + const T& operator()() const + { + return fpSample; + } + }; + }; +}; + +#endif diff --git a/tests/sqlite3/usage/IntegralTest.cpp b/tests/sqlite3/usage/IntegralTest.cpp new file mode 100644 index 00000000..cef172d1 --- /dev/null +++ b/tests/sqlite3/usage/IntegralTest.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "IntegralSample.h" +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include +#include + +namespace sql = sqlpp::sqlite3; + +const auto intSample = IntegralSample{}; + +template +auto require_equal(int line, const L& l, const R& r) -> void +{ + if (l != r) + { + std::cerr << line << ": "; + serialize(::sqlpp::wrap_operand_t{l}, std::cerr); + std::cerr << " != "; + serialize(::sqlpp::wrap_operand_t{r}, std::cerr); + throw std::runtime_error("Unexpected result"); + } +} + +int main() +{ + sql::connection_config config; + config.path_to_database = ":memory:"; + config.flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + config.debug = true; + + sql::connection db(config); + db.execute(R"(CREATE TABLE integral_sample ( + signed_value INTEGER, + unsigned_value INTEGER + ))"); + + // The connector supports uint64_t values and will always retrieve the correct value from the database. + // Sqlite3 stores the values as int64_t internally though, so big uint64_t values will be converted + // and the library has to intepret the int64_t values correctly as uint64_t. + // Therefore, we test uint64_t values in an out of the range of int64_t and test if they are retrieved + // correctly from the database in both cases. + uint64_t uint64_t_value_supported = std::numeric_limits::max(); + int64_t int64_t_value_max = std::numeric_limits::max(); + + uint64_t uint64_t_value_unsupported = std::numeric_limits::max(); + int64_t int64_t_value_min = std::numeric_limits::min(); + + std::size_t size_t_value_max = std::numeric_limits::max(); + std::size_t size_t_value_min = std::numeric_limits::min(); + + uint32_t uint32_t_value = std::numeric_limits::max(); + int32_t int32_t_value = std::numeric_limits::max(); + + db(insert_into(intSample).set(intSample.signedValue = int64_t_value_max, + intSample.unsignedValue = uint64_t_value_supported)); + + auto prepared_insert = + db.prepare(insert_into(intSample).set(intSample.signedValue = parameter(intSample.signedValue), + intSample.unsignedValue = parameter(intSample.unsignedValue))); + prepared_insert.params.signedValue = int64_t_value_min; + prepared_insert.params.unsignedValue = uint64_t_value_unsupported; + db(prepared_insert); + + db(insert_into(intSample).set(intSample.signedValue = size_t_value_min, intSample.unsignedValue = size_t_value_max)); + db(insert_into(intSample).set(intSample.signedValue = int32_t_value, intSample.unsignedValue = uint32_t_value)); + + auto q = select(intSample.signedValue, intSample.unsignedValue).from(intSample).unconditionally(); + + auto rows = db(q); + + require_equal(__LINE__, rows.front().signedValue.value(), int64_t_value_max); + require_equal(__LINE__, rows.front().unsignedValue.value(), uint64_t_value_supported); + rows.pop_front(); + + require_equal(__LINE__, rows.front().signedValue.value(), int64_t_value_min); + require_equal(__LINE__, rows.front().unsignedValue.value(), uint64_t_value_unsupported); + rows.pop_front(); + + require_equal(__LINE__, rows.front().signedValue.value(), size_t_value_min); + require_equal(__LINE__, rows.front().unsignedValue.value(), size_t_value_max); + rows.pop_front(); + + require_equal(__LINE__, rows.front().signedValue.value(), int32_t_value); + require_equal(__LINE__, rows.front().unsignedValue.value(), uint32_t_value); + rows.pop_front(); + + return 0; +} diff --git a/tests/sqlite3/usage/SampleTest.cpp b/tests/sqlite3/usage/SampleTest.cpp new file mode 100644 index 00000000..f3e2ca0f --- /dev/null +++ b/tests/sqlite3/usage/SampleTest.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TabSample.h" +#include +#include +#include + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include +#include +#include + +SQLPP_ALIAS_PROVIDER(left) +SQLPP_ALIAS_PROVIDER(pragma) +SQLPP_ALIAS_PROVIDER(sub) + +namespace sql = sqlpp::sqlite3; +int main() +{ + sql::connection_config config; + config.path_to_database = ":memory:"; + config.flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + config.debug = true; + + sql::connection db(config); + db.execute(R"(CREATE TABLE tab_sample ( + alpha INTEGER PRIMARY KEY, + beta varchar(255) DEFAULT NULL, + gamma bool DEFAULT NULL + ))"); + db.execute(R"(CREATE TABLE tab_foo ( + omega bigint(20) DEFAULT NULL + ))"); + + const auto tab = TabSample{}; + + // clear the table + db(remove_from(tab).unconditionally()); + + // explicit all_of(tab) + for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) + { + std::cerr << "row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma << std::endl; + }; + std::cerr << __FILE__ << ": " << __LINE__ << std::endl; + // selecting a table implicitly expands to all_of(tab) + for (const auto& row : db(select(all_of(tab)).from(tab).unconditionally())) + { + std::cerr << "row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma << std::endl; + }; + // insert + std::cerr << "no of required columns: " << TabSample::_required_insert_columns::size::value << std::endl; + db(insert_into(tab).default_values()); + std::cout << "Last Insert ID: " << db.last_insert_id() << "\n"; + db(insert_into(tab).set(tab.gamma = true)); + std::cout << "Last Insert ID: " << db.last_insert_id() << "\n"; + auto di = dynamic_insert_into(db, tab).dynamic_set(tab.gamma = true); + di.insert_list.add(tab.beta = ""); + db(di); + + // update + db(update(tab).set(tab.gamma = false).where(tab.alpha.in(1))); + db(update(tab).set(tab.gamma = false).where(tab.alpha.in(sqlpp::value_list(std::vector{1, 2, 3, 4})))); + + // remove + db(remove_from(tab).where(tab.alpha == tab.alpha + 3)); + + auto result = db(select(all_of(tab)).from(tab).unconditionally()); + std::cerr << "Accessing a field directly from the result (using the current row): " << result.begin()->alpha + << std::endl; + std::cerr << "Can do that again, no problem: " << result.begin()->alpha << std::endl; + + auto tx = start_transaction(db); + TabFoo foo; + for (const auto& row : db(select(all_of(tab), select(max(foo.omega)).from(foo).where(foo.omega > tab.alpha)) + .from(tab) + .unconditionally())) + { + int x = row.alpha; + int a = row.max; + std::cout << x << ", " << a << std::endl; + } + tx.commit(); + + for (const auto& row : db(select(tab.alpha).from(tab.join(foo).on(tab.alpha == foo.omega)).unconditionally())) + { + std::cerr << row.alpha << std::endl; + } + + for (const auto& row : + db(select(tab.alpha).from(tab.left_outer_join(foo).on(tab.alpha == foo.omega)).unconditionally())) + { + std::cerr << row.alpha << std::endl; + } + + auto ps = db.prepare(select(all_of(tab)) + .from(tab) + .where(tab.alpha != parameter(tab.alpha) and tab.beta != parameter(tab.beta) and + tab.gamma != parameter(tab.gamma))); + ps.params.alpha = 7; + ps.params.beta = "wurzelbrunft"; + ps.params.gamma = true; + for (const auto& row : db(ps)) + { + std::cerr << "bound result: alpha: " << row.alpha << std::endl; + std::cerr << "bound result: beta: " << row.beta << std::endl; + std::cerr << "bound result: gamma: " << row.gamma << std::endl; + } + + std::cerr << "--------" << std::endl; + ps.params.alpha = sqlpp::eval(db, "last_insert_rowid()"); + ps.params.gamma = "false"; + for (const auto& row : db(ps)) + { + std::cerr << "bound result: alpha: " << row.alpha << std::endl; + std::cerr << "bound result: beta: " << row.beta << std::endl; + std::cerr << "bound result: gamma: " << row.gamma << std::endl; + } + + std::cerr << "--------" << std::endl; + ps.params.beta = "kaesekuchen"; + for (const auto& row : db(ps)) + { + std::cerr << "bound result: alpha: " << row.alpha << std::endl; + std::cerr << "bound result: beta: " << row.beta << std::endl; + std::cerr << "bound result: gamma: " << row.gamma << std::endl; + } + + auto pi = db.prepare(insert_into(tab).set(tab.beta = parameter(tab.beta), tab.gamma = true)); + pi.params.beta = "prepared cake"; + std::cerr << "Inserted: " << db(pi) << std::endl; + + auto pu = db.prepare(update(tab).set(tab.gamma = parameter(tab.gamma)).where(tab.beta == "prepared cake")); + pu.params.gamma = false; + std::cerr << "Updated: " << db(pu) << std::endl; + + auto pr = db.prepare(remove_from(tab).where(tab.beta != parameter(tab.beta))); + pr.params.beta = "prepared cake"; + std::cerr << "Deleted lines: " << db(pr) << std::endl; + + // Check that a prepared select is default-constructible + { + auto s = select(all_of(tab)) + .from(tab) + .where((tab.beta.like(parameter(tab.beta)) and tab.alpha == parameter(tab.alpha)) or + tab.gamma != parameter(tab.gamma)); + using P = decltype(db.prepare(s)); + P p; // You must not use this one yet! + p = db.prepare(s); + } + + auto i = db(sqlpp::sqlite3::insert_or_replace_into(tab).set(tab.beta = "test", tab.gamma = true)); + std::cerr << i << std::endl; + + i = db(sqlpp::sqlite3::insert_or_ignore_into(tab).set(tab.beta = "test", tab.gamma = true)); + std::cerr << i << std::endl; + + assert(db(select(count(tab.alpha)).from(tab).unconditionally()).begin()->count); + assert( + db(select(all_of(tab)).from(tab).where(tab.alpha.not_in(select(tab.alpha).from(tab).unconditionally()))).empty()); + + auto x = custom_query(sqlpp::verbatim("PRAGMA user_version = "), 1); + db(x); + int pragmaValue = + db(custom_query(sqlpp::verbatim("PRAGMA user_version")).with_result_type_of(select(sqlpp::value(1).as(pragma)))) + .front() + .pragma; + std::cerr << pragmaValue << std::endl; + + // Testing sub select tables and unconditional joins + const auto subQuery = select(tab.alpha).from(tab).unconditionally().as(sub); + for (const auto& row : db(select(subQuery.alpha).from(subQuery).unconditionally())) + { + std::cerr << row.alpha; + } + + for (const auto& row : db(select(subQuery.alpha).from(tab.inner_join(subQuery).unconditionally()).unconditionally())) + { + std::cerr << row.alpha; + } + + return 0; +} diff --git a/tests/sqlite3/usage/SelectTest.cpp b/tests/sqlite3/usage/SelectTest.cpp new file mode 100644 index 00000000..f781a84c --- /dev/null +++ b/tests/sqlite3/usage/SelectTest.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * Copyright (c) 2017, Juan Dent + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TabSample.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +SQLPP_ALIAS_PROVIDER(left) + +namespace sql = sqlpp::sqlite3; +const auto tab = TabSample{}; + +void testSelectAll(sql::connection& db, size_t expectedRowCount) +{ + std::cerr << "--------------------------------------" << std::endl; + size_t i = 0; + for (const auto& row : db(sqlpp::select(all_of(tab)).from(tab).unconditionally())) + { + ++i; + std::cerr << ">>> row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma + << std::endl; + assert(static_cast(row.alpha) == i); + }; + assert(i == expectedRowCount); + + auto preparedSelectAll = db.prepare(sqlpp::select(all_of(tab)).from(tab).unconditionally()); + i = 0; + for (const auto& row : db(preparedSelectAll)) + { + ++i; + std::cerr << ">>> row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma + << std::endl; + assert(static_cast(row.alpha) == i); + }; + assert(i == expectedRowCount); + std::cerr << "--------------------------------------" << std::endl; +} + +namespace string_util +{ + std::string ltrim(std::string str, const std::string& chars = "\t\n\v\f\r ") + { + str.erase(0, str.find_first_not_of(chars)); + return str; + } + + std::string rtrim(std::string str, const std::string& chars = "\t\n\v\f\r ") + { + str.erase(str.find_last_not_of(chars) + 1); + return str; + } + + std::string trim(std::string str, const std::string& chars = "\t\n\v\f\r ") + { + return ltrim(rtrim(str, chars), chars); + } +} + +int main() +{ + sql::connection db({":memory:", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "", true}); + db.execute(R"(CREATE TABLE tab_sample ( + alpha INTEGER PRIMARY KEY, + beta varchar(255) DEFAULT NULL, + gamma bool DEFAULT NULL + ))"); + + testSelectAll(db, 0); + db(insert_into(tab).default_values()); + testSelectAll(db, 1); + db(insert_into(tab).set(tab.gamma = true, tab.beta = " cheesecake ")); + testSelectAll(db, 2); + db(insert_into(tab).set(tab.gamma = true, tab.beta = " cheesecake ")); + testSelectAll(db, 3); + + // test functions and operators + db(select(all_of(tab)).from(tab).where(tab.alpha.is_null())); + db(select(all_of(tab)).from(tab).where(tab.alpha.is_not_null())); + db(select(all_of(tab)).from(tab).where(tab.alpha.in(1, 2, 3))); + db(select(all_of(tab)).from(tab).where(tab.alpha.in(sqlpp::value_list(std::vector{1, 2, 3, 4})))); + db(select(all_of(tab)).from(tab).where(tab.alpha.not_in(1, 2, 3))); + db(select(all_of(tab)).from(tab).where(tab.alpha.not_in(sqlpp::value_list(std::vector{1, 2, 3, 4})))); + db(select(count(tab.alpha)).from(tab).unconditionally()); + db(select(avg(tab.alpha)).from(tab).unconditionally()); + db(select(max(tab.alpha)).from(tab).unconditionally()); + db(select(min(tab.alpha)).from(tab).unconditionally()); + db(select(exists(select(tab.alpha).from(tab).where(tab.alpha > 7))).from(tab).unconditionally()); + db(select(trim(tab.beta)).from(tab).unconditionally()); + + // db(select(not_exists(select(tab.alpha).from(tab).where(tab.alpha > 7))).from(tab)); + // db(select(all_of(tab)).from(tab).where(tab.alpha == any(select(tab.alpha).from(tab).where(tab.alpha < 3)))); + + db(select(all_of(tab)).from(tab).where((tab.alpha + tab.alpha) > 3)); + db(select(all_of(tab)).from(tab).where((tab.beta + tab.beta) == "")); + db(select(all_of(tab)).from(tab).where((tab.beta + tab.beta).like(R"(%'\"%)"))); + + // update + db(update(tab).set(tab.gamma = false).where(tab.alpha.in(1))); + db(update(tab).set(tab.gamma = false).where(tab.alpha.in(sqlpp::value_list(std::vector{1, 2, 3, 4})))); + + // remove + db(remove_from(tab).where(tab.alpha == tab.alpha + 3)); + + auto result = db(select(all_of(tab)).from(tab).unconditionally()); + std::cerr << "Accessing a field directly from the result (using the current row): " << result.begin()->alpha + << std::endl; + std::cerr << "Can do that again, no problem: " << result.begin()->alpha << std::endl; + + std::cerr << "--------------------------------------" << std::endl; + auto tx = start_transaction(db); + for (const auto& row : db(select(all_of(tab), select(max(tab.alpha)).from(tab)).from(tab).unconditionally())) + { + int x = row.alpha; + int a = row.max; + std::cout << ">>>" << x << ", " << a << std::endl; + } + for (const auto& row : + db(select(tab.alpha, tab.beta, tab.gamma, trim(tab.beta)) + .from(tab) + .unconditionally())) + { + std::cerr << ">>> row.alpha: " << row.alpha << ", row.beta: " << row.beta << ", row.gamma: " << row.gamma + << ", row.trim: '" << row.trim << "'" << std::endl; + // check trim + assert(string_util::trim(row.beta.value()) == row.trim.value()); + // end + }; + + for (const auto& row : db(select(all_of(tab), select(trim(tab.beta)).from(tab)).from(tab).unconditionally())) + { + int x = row.alpha; + std::string a = row.trim; + std::cout << ">>>" << x << ", " << a << std::endl; + } + + tx.commit(); + std::cerr << "--------------------------------------" << std::endl; + + return 0; +} diff --git a/tests/sqlite3/usage/TabSample.h b/tests/sqlite3/usage/TabSample.h new file mode 100644 index 00000000..27b0db52 --- /dev/null +++ b/tests/sqlite3/usage/TabSample.h @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2013 - 2015, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SQLPP_TAB_SAMPLE_H +#define SQLPP_TAB_SAMPLE_H + +#include +#include +#include + +namespace TabFoo_ +{ + struct Omega + { + struct _alias_t + { + static constexpr const char _literal[] = "omega"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T omega; + T& operator()() + { + return omega; + } + const T& operator()() const + { + return omega; + } + }; + }; + using _traits = ::sqlpp::make_traits<::sqlpp::bigint>; + }; +} + +struct TabFoo : sqlpp::table_t +{ + using _value_type = sqlpp::no_value_t; + struct _alias_t + { + static constexpr const char _literal[] = "tab_foo"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T tabFoo; + T& operator()() + { + return tabFoo; + } + const T& operator()() const + { + return tabFoo; + } + }; + }; +}; + +namespace TabSample_ +{ + struct Alpha + { + struct _alias_t + { + static constexpr const char _literal[] = "alpha"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T alpha; + T& operator()() + { + return alpha; + } + const T& operator()() const + { + return alpha; + } + }; + }; + using _traits = ::sqlpp::make_traits<::sqlpp::bigint, + ::sqlpp::tag::must_not_insert, + ::sqlpp::tag::must_not_update, + ::sqlpp::tag::can_be_null>; + }; + + struct Beta + { + struct _alias_t + { + static constexpr const char _literal[] = "beta"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T beta; + T& operator()() + { + return beta; + } + const T& operator()() const + { + return beta; + } + }; + }; + using _traits = ::sqlpp::make_traits<::sqlpp::varchar, ::sqlpp::tag::must_not_update, ::sqlpp::tag::can_be_null>; + }; + + struct Gamma + { + struct _alias_t + { + static constexpr const char _literal[] = "gamma"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T gamma; + T& operator()() + { + return gamma; + } + const T& operator()() const + { + return gamma; + } + }; + }; + using _traits = ::sqlpp::make_traits<::sqlpp::boolean>; + }; +} + +struct TabSample : sqlpp::table_t +{ + using _value_type = sqlpp::no_value_t; + struct _alias_t + { + static constexpr const char _literal[] = "tab_sample"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T tabSample; + T& operator()() + { + return tabSample; + } + const T& operator()() const + { + return tabSample; + } + }; + }; +}; + +namespace TabDateTime_ +{ + struct ColDayPoint + { + struct _alias_t + { + static constexpr const char _literal[] = "col_day_point"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T colDayPoint; + T& operator()() + { + return colDayPoint; + } + const T& operator()() const + { + return colDayPoint; + } + }; + }; + using _traits = sqlpp::make_traits; + }; + struct ColTimePoint + { + struct _alias_t + { + static constexpr const char _literal[] = "col_time_point"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T colTimePoint; + T& operator()() + { + return colTimePoint; + } + const T& operator()() const + { + return colTimePoint; + } + }; + }; + using _traits = sqlpp::make_traits; + }; +} + +struct TabDateTime : sqlpp::table_t +{ + struct _alias_t + { + static constexpr const char _literal[] = "tab_date_time"; + using _name_t = sqlpp::make_char_sequence; + template + struct _member_t + { + T tabDateTime; + T& operator()() + { + return tabDateTime; + } + const T& operator()() const + { + return tabDateTime; + } + }; + }; +}; + +#endif diff --git a/tests/sqlite3/usage/TabSample.sql b/tests/sqlite3/usage/TabSample.sql new file mode 100644 index 00000000..fa14c9e4 --- /dev/null +++ b/tests/sqlite3/usage/TabSample.sql @@ -0,0 +1,5 @@ +CREATE TABLE tab_sample ( + alpha bigint(20) DEFAULT NULL, + beta tinyint(1) DEFAULT NULL, + gamma varchar(255) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1; diff --git a/tests/sqlite3/usage/TransactionTest.cpp b/tests/sqlite3/usage/TransactionTest.cpp new file mode 100644 index 00000000..300d4bee --- /dev/null +++ b/tests/sqlite3/usage/TransactionTest.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TabSample.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include +#include + +namespace sql = sqlpp::sqlite3; + +SQLPP_ALIAS_PROVIDER(pragma) + +int main() +{ + sql::connection db({":memory:", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "", true}); + + std::cerr << "--------------------------------------" << std::endl; + + auto current_level = db.get_default_isolation_level(); + std::cout << "Expecting default isolation level = 1, is " << static_cast(current_level) << std::endl; + assert(current_level == sqlpp::isolation_level::serializable); + + int pragmaValue = db(custom_query(sqlpp::verbatim("PRAGMA read_uncommitted")) + .with_result_type_of(select(sqlpp::value(1).as(pragma)))) + .front() + .pragma; + assert(pragmaValue == 0); + + std::cerr << "Expecting read_uncommitted = 0, is: " << pragmaValue << std::endl; + db.set_default_isolation_level(sqlpp::isolation_level::read_uncommitted); + auto tx = start_transaction(db); + pragmaValue = db(custom_query(sqlpp::verbatim("PRAGMA read_uncommitted")) + .with_result_type_of(select(sqlpp::value(1).as(pragma)))) + .front() + .pragma; + std::cerr << "Now expecting read_uncommitted = 1, is: " << pragmaValue << std::endl; + assert(pragmaValue == 1); + + current_level = db.get_default_isolation_level(); + std::cout << "Now expecting default isolation level = 4, is " << static_cast(current_level) << std::endl; + assert(current_level == sqlpp::isolation_level::read_uncommitted); + + tx.commit(); + std::cerr << "--------------------------------------" << std::endl; + + return 0; +} diff --git a/tests/sqlite3/usage/UnionTest.cpp b/tests/sqlite3/usage/UnionTest.cpp new file mode 100644 index 00000000..17c6b660 --- /dev/null +++ b/tests/sqlite3/usage/UnionTest.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TabSample.h" +#include +#include + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include + +namespace sql = sqlpp::sqlite3; +const auto tab = TabSample{}; + +int main() +{ + sql::connection_config config; + config.path_to_database = ":memory:"; + config.flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + config.debug = true; + + sql::connection db(config); + db.execute(R"(CREATE TABLE tab_sample ( + alpha INTEGER PRIMARY KEY, + beta varchar(255) DEFAULT NULL, + gamma bool DEFAULT NULL + ))"); + + auto u = select(all_of(tab)).from(tab).unconditionally().union_all(select(all_of(tab)).from(tab).unconditionally()); + + for (const auto& row : db(u)) + { + std::cout << row.alpha << row.beta << row.gamma << std::endl; + } + + for (const auto& row : db(u.union_distinct(select(all_of(tab)).from(tab).unconditionally()))) + { + std::cout << row.alpha << row.beta << row.gamma << std::endl; + } + + return 0; +} diff --git a/tests/sqlite3/usage/WithTest.cpp b/tests/sqlite3/usage/WithTest.cpp new file mode 100644 index 00000000..ee62b01f --- /dev/null +++ b/tests/sqlite3/usage/WithTest.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013 - 2016, Roland Bock + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TabSample.h" +#include +#include +#include + +#ifdef SQLPP_USE_SQLCIPHER +#include +#else +#include +#endif +#include +#include + +namespace sql = sqlpp::sqlite3; +const auto tab = TabSample{}; + +int main() +{ +#if SQLITE_VERSION_NUMBER >= 3008003 + sql::connection_config config; + config.path_to_database = ":memory:"; + config.flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + config.debug = true; + + sql::connection db(config); + db.execute(R"(CREATE TABLE tab_sample ( + alpha INTEGER PRIMARY KEY, + beta varchar(255) DEFAULT NULL, + gamma bool DEFAULT NULL + ))"); + + auto a = sqlpp::cte(sqlpp::alias::a).as(select(all_of(tab)).from(tab).where(tab.alpha > 3)); + for (const auto& row : db(with(a)(select(a.alpha).from(a)).unconditionally())) + { + std::cout << row.alpha << std::endl; + } + + for (const auto& row : + db(with(a.union_all(select(all_of(a)).from(a).unconditionally()))(select(all_of(a)).from(a)).unconditionally())) + { + std::cout << row.alpha << row.beta << row.gamma << std::endl; + } + +#endif + return 0; +}