added sqlite connection class (progress)
This commit is contained in:
parent
f4f5c00eec
commit
715f4dff8f
|
|
@ -2,15 +2,24 @@ cmake_minimum_required(VERSION 3.26)
|
||||||
project(query)
|
project(query)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
|
||||||
|
|
||||||
find_package(ODBC REQUIRED)
|
find_package(ODBC REQUIRED)
|
||||||
|
find_package(SQLite3 REQUIRED)
|
||||||
|
|
||||||
|
message(STATUS "Found SQLite3 ${SQLite3_VERSION}")
|
||||||
|
message(STATUS "Adding SQLite3 include directory: ${SQLite3_INCLUDE_DIRS}")
|
||||||
|
message(STATUS "Adding SQLite3 libs: ${SQLite3_LIBRARIES}")
|
||||||
|
|
||||||
|
message(STATUS "Common flags ${CMAKE_CXX_FLAGS}")
|
||||||
|
message(STATUS "Debug flags ${CMAKE_CXX_FLAGS_DEBUG}")
|
||||||
|
message(STATUS "Relase flags ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||||
|
|
||||||
|
message(STATUS "Linker flags ${CMAKE_EXE_LINKER_FLAGS}")
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
add_subdirectory(backends)
|
||||||
|
|
||||||
add_executable(query main.cpp
|
add_executable(query main.cpp)
|
||||||
include/matador/sql/connection_impl.hpp
|
|
||||||
include/matador/sql/connection_info.hpp)
|
|
||||||
target_link_libraries(query matador)
|
target_link_libraries(query matador)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
add_subdirectory(sqlite)
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
set(HEADER
|
||||||
|
include/sqlite_connection.hpp
|
||||||
|
include/sqlite_error.hpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
src/sqlite_connection.cpp
|
||||||
|
src/sqlite_error.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(matador-sqlite SHARED ${SOURCES} ${HEADER})
|
||||||
|
target_include_directories(matador-sqlite PRIVATE
|
||||||
|
${PROJECT_SOURCE_DIR}/include
|
||||||
|
${PROJECT_SOURCE_DIR}/backends/sqlite/include
|
||||||
|
${SQLite3_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
target_link_libraries(matador-sqlite matador ${SQLite3_LIBRARIES})
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef QUERY_SQLITE_CONNECTION_HPP
|
||||||
|
#define QUERY_SQLITE_CONNECTION_HPP
|
||||||
|
|
||||||
|
#include "matador/sql/connection_impl.hpp"
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
namespace matador::backends::sqlite {
|
||||||
|
|
||||||
|
class sqlite_connection : public matador::sql::connection_impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit sqlite_connection(sql::connection_info info);
|
||||||
|
void open() override;
|
||||||
|
void close() override;
|
||||||
|
bool is_open() override;
|
||||||
|
|
||||||
|
void execute(const std::string &stmt) override;
|
||||||
|
void prepare(const std::string &stmt) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sqlite3 *sqlite_db_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif //QUERY_SQLITE_CONNECTION_HPP
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef QUERY_SQLITE_ERROR_HPP
|
||||||
|
#define QUERY_SQLITE_ERROR_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct sqlite3;
|
||||||
|
|
||||||
|
namespace matador::backends::sqlite {
|
||||||
|
|
||||||
|
void throw_sqlite_error(int ec, sqlite3 *db, const std::string &source);
|
||||||
|
void throw_sqlite_error(int ec, sqlite3 *db, const std::string &source, const std::string &sql);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //QUERY_SQLITE_ERROR_HPP
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
#include "sqlite_connection.hpp"
|
||||||
|
#include "sqlite_error.hpp"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace matador::backends::sqlite {
|
||||||
|
|
||||||
|
sqlite_connection::sqlite_connection(sql::connection_info info)
|
||||||
|
: connection_impl(std::move(info)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void sqlite_connection::open()
|
||||||
|
{
|
||||||
|
const auto ret = sqlite3_open(info().database.c_str(), &sqlite_db_);
|
||||||
|
|
||||||
|
if (ret != SQLITE_OK) {
|
||||||
|
throw_sqlite_error(ret, sqlite_db_, "open");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sqlite_connection::close()
|
||||||
|
{
|
||||||
|
int ret = sqlite3_close(sqlite_db_);
|
||||||
|
|
||||||
|
throw_sqlite_error(ret, sqlite_db_, "close");
|
||||||
|
|
||||||
|
sqlite_db_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sqlite_connection::is_open()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sqlite_connection::execute(const std::string &stmt)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void sqlite_connection::prepare(const std::string &stmt)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include "sqlite_error.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
namespace matador::backends::sqlite {
|
||||||
|
|
||||||
|
void throw_sqlite_error(int ec, sqlite3 *db, const std::string &source)
|
||||||
|
{
|
||||||
|
if (ec != SQLITE_OK) {
|
||||||
|
std::stringstream msg;
|
||||||
|
msg << "sqlite error (" << source << "): " << sqlite3_errmsg(db);
|
||||||
|
throw std::logic_error(msg.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void throw_sqlite_error(int ec, sqlite3 *db, const std::string &source, const std::string &sql)
|
||||||
|
{
|
||||||
|
if (ec != SQLITE_OK) {
|
||||||
|
std::stringstream msg;
|
||||||
|
msg << "sqlite error (" << source << ", sql: " << sql << "): " << sqlite3_errmsg(db);
|
||||||
|
throw std::logic_error(msg.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef QUERY_CONNECTION_HPP
|
#ifndef QUERY_CONNECTION_HPP
|
||||||
#define QUERY_CONNECTION_HPP
|
#define QUERY_CONNECTION_HPP
|
||||||
|
|
||||||
#include "matador/sql/connection_intermediates.hpp"
|
#include "matador/sql/query_intermediates.hpp"
|
||||||
#include "matador/sql/dialect.hpp"
|
#include "matador/sql/dialect.hpp"
|
||||||
#include "matador/sql/query_builder.hpp"
|
#include "matador/sql/query_builder.hpp"
|
||||||
|
|
||||||
|
|
@ -12,20 +12,21 @@ namespace matador::sql {
|
||||||
class connection
|
class connection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
connection();
|
connection() = default;
|
||||||
query_create_intermediate create();
|
explicit connection(std::string dns);
|
||||||
query_drop_intermediate drop();
|
|
||||||
query_select_intermediate select(std::initializer_list<std::string> column_names);
|
void open();
|
||||||
query_insert_intermediate insert();
|
void close();
|
||||||
query_update_intermediate update(const std::string &table);
|
[[nodiscard]] bool is_open() const;
|
||||||
query_delete_intermediate remove();
|
|
||||||
|
[[nodiscard]] const std::string& dns() const;
|
||||||
|
|
||||||
query_result<record> fetch(const std::string &sql);
|
query_result<record> fetch(const std::string &sql);
|
||||||
std::pair<size_t, std::string> execute(const std::string &sql);
|
std::pair<size_t, std::string> execute(const std::string &sql);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
dialect dialect_;
|
std::string dns_;
|
||||||
query_builder query_;
|
bool is_open_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
#ifndef QUERY_CONNECTION_POOL_HPP
|
||||||
|
#define QUERY_CONNECTION_POOL_HPP
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <queue>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
namespace matador::sql {
|
||||||
|
|
||||||
|
template < class Connection >
|
||||||
|
class connection_pool;
|
||||||
|
|
||||||
|
template < class Connection >
|
||||||
|
class connection_ptr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
connection_ptr(Connection *c, connection_pool<Connection> &pool)
|
||||||
|
: connection_(c), pool_(pool) {}
|
||||||
|
~connection_ptr();
|
||||||
|
connection_ptr(const connection_ptr &) = delete;
|
||||||
|
connection_ptr& operator=(const connection_ptr &) = delete;
|
||||||
|
connection_ptr(connection_ptr &&) noexcept = default;
|
||||||
|
connection_ptr& operator=(connection_ptr &&) noexcept = default;
|
||||||
|
|
||||||
|
Connection* operator->() { return connection_; }
|
||||||
|
Connection& operator*() { return *connection_; }
|
||||||
|
|
||||||
|
[[nodiscard]] bool valid() const { return connection_ != nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class connection_pool<Connection>;
|
||||||
|
|
||||||
|
Connection *connection_;
|
||||||
|
connection_pool<Connection> &pool_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < class Connection >
|
||||||
|
class connection_pool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
connection_pool(const std::string &db, unsigned int count) {
|
||||||
|
connection_repo_.reserve(count);
|
||||||
|
for (auto i = 0U; i < count; ++i) {
|
||||||
|
connection_repo_.emplace_back(db + std::to_string(i+1));
|
||||||
|
idle_connections_.push(&connection_repo_.back());
|
||||||
|
idle_connections_.back()->open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connection_ptr<Connection> acquire() {
|
||||||
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
|
if (idle_connections_.empty()) {
|
||||||
|
return {nullptr, *this};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptr = idle_connections_.front();
|
||||||
|
idle_connections_.pop();
|
||||||
|
inuse_connections_.insert(ptr);
|
||||||
|
return { ptr, *this };
|
||||||
|
}
|
||||||
|
|
||||||
|
void release(Connection *c) {
|
||||||
|
if (c == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
|
|
||||||
|
if (inuse_connections_.erase(c) > 0) {
|
||||||
|
idle_connections_.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void release(connection_ptr<Connection> &c) {
|
||||||
|
release(c.connection_);
|
||||||
|
c.connection_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t size() const { return connection_repo_.size(); }
|
||||||
|
std::size_t idle() const {
|
||||||
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
|
return idle_connections_.size();
|
||||||
|
}
|
||||||
|
std::size_t inuse() const {
|
||||||
|
std::lock_guard<std::mutex> guard(mutex_);
|
||||||
|
return inuse_connections_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable std::mutex mutex_;
|
||||||
|
std::vector<Connection> connection_repo_;
|
||||||
|
using pointer = Connection*;
|
||||||
|
using connections = std::queue<pointer>;
|
||||||
|
using connection_set = std::unordered_set<pointer>;
|
||||||
|
connections idle_connections_;
|
||||||
|
connection_set inuse_connections_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Connection>
|
||||||
|
connection_ptr<Connection>::~connection_ptr() {
|
||||||
|
pool_.release(connection_);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //QUERY_CONNECTION_POOL_HPP
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef QUERY_CONNECTION_INTERMEDIATES_HPP
|
#ifndef QUERY_QUERY_INTERMEDIATES_HPP
|
||||||
#define QUERY_CONNECTION_INTERMEDIATES_HPP
|
#define QUERY_QUERY_INTERMEDIATES_HPP
|
||||||
|
|
||||||
#include "matador/sql/column.hpp"
|
#include "matador/sql/column.hpp"
|
||||||
#include "matador/sql/key_value_pair.hpp"
|
#include "matador/sql/key_value_pair.hpp"
|
||||||
|
|
@ -11,20 +11,20 @@
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
class basic_condition;
|
class basic_condition;
|
||||||
class connection;
|
class session;
|
||||||
class query_builder;
|
class query_builder;
|
||||||
|
|
||||||
class query_intermediate
|
class query_intermediate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
query_intermediate(connection &db, query_builder &query);
|
query_intermediate(session &db, query_builder &query);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
connection& db();
|
session& db();
|
||||||
query_builder& query();
|
query_builder& query();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
connection &db_;
|
session &db_;
|
||||||
query_builder &query_;
|
query_builder &query_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -195,4 +195,4 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif //QUERY_CONNECTION_INTERMEDIATES_HPP
|
#endif //QUERY_QUERY_INTERMEDIATES_HPP
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef QUERY_SESSION_HPP
|
||||||
|
#define QUERY_SESSION_HPP
|
||||||
|
|
||||||
|
#include "matador/sql/connection.hpp"
|
||||||
|
#include "matador/sql/connection_pool.hpp"
|
||||||
|
|
||||||
|
namespace matador::sql {
|
||||||
|
|
||||||
|
class session
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit session(connection_pool<connection> &pool);
|
||||||
|
|
||||||
|
query_create_intermediate create();
|
||||||
|
query_drop_intermediate drop();
|
||||||
|
query_select_intermediate select(std::initializer_list<std::string> column_names);
|
||||||
|
query_insert_intermediate insert();
|
||||||
|
query_update_intermediate update(const std::string &table);
|
||||||
|
query_delete_intermediate remove();
|
||||||
|
|
||||||
|
query_result<record> fetch(const std::string &sql);
|
||||||
|
std::pair<size_t, std::string> execute(const std::string &sql);
|
||||||
|
|
||||||
|
private:
|
||||||
|
connection_pool<connection> &pool_;
|
||||||
|
dialect dialect_;
|
||||||
|
query_builder query_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif //QUERY_SESSION_HPP
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
#ifndef QUERY_LIBRARY_HPP
|
||||||
|
#define QUERY_LIBRARY_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
|
#define _WINSOCKAPI_
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace matador::utils {
|
||||||
|
|
||||||
|
#ifndef MATADOR_DOXYGEN_DOC
|
||||||
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
|
typedef FARPROC func_ptr;
|
||||||
|
#else
|
||||||
|
typedef void *func_ptr;
|
||||||
|
#endif
|
||||||
|
#endif /* MATADOR_DOXYGEN_DOC */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class library
|
||||||
|
* @brief Helps to load and unload
|
||||||
|
* external libraries.
|
||||||
|
*
|
||||||
|
* This class represents a loader and un-loader
|
||||||
|
* for an external library. The path to the library
|
||||||
|
* is given by a string.
|
||||||
|
* It can be loaded and unloaded. Furthermore it
|
||||||
|
* provides a method to get a pointer to an function
|
||||||
|
* exported by the library. The function is identified
|
||||||
|
* by a name.
|
||||||
|
*/
|
||||||
|
class library
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create a unspecified library serializable
|
||||||
|
*/
|
||||||
|
library() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a library for the given lib path
|
||||||
|
*
|
||||||
|
* @param lib The path to the library to map.
|
||||||
|
*/
|
||||||
|
explicit library(std::string lib);
|
||||||
|
|
||||||
|
~library();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the underlying library.
|
||||||
|
* If the library path is invalid
|
||||||
|
* or the library cannot be loaded
|
||||||
|
* false is returned.
|
||||||
|
*
|
||||||
|
* @return True on successful library loading.
|
||||||
|
*/
|
||||||
|
bool load();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the library (and subsequently close and
|
||||||
|
* overwrite an already instantiated library) and
|
||||||
|
* load the underlying library. If the library
|
||||||
|
* path is invalid or the library cannot be loaded
|
||||||
|
* false is returned.
|
||||||
|
*
|
||||||
|
* @param lib The path to the library to load.
|
||||||
|
* @return True on successful library loading.
|
||||||
|
*/
|
||||||
|
bool load(const std::string &lib);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unload an loaded library. If
|
||||||
|
* the library isn't loaded or an
|
||||||
|
* error occurred while unloading
|
||||||
|
* false is returned.
|
||||||
|
*
|
||||||
|
* @return True on successful unloading.
|
||||||
|
*/
|
||||||
|
bool unload();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the pointer to the exported
|
||||||
|
* function of the library identified
|
||||||
|
* by the given name.
|
||||||
|
*
|
||||||
|
* @param f The name of the exported function.
|
||||||
|
* @return The pointer to the function.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] func_ptr function(const std::string &f) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string lib_;
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__MINGW32__)
|
||||||
|
HMODULE handle_ = nullptr;
|
||||||
|
#else
|
||||||
|
void *handle_ = nullptr;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //QUERY_LIBRARY_HPP
|
||||||
|
|
@ -5,10 +5,11 @@ set(SQL_SOURCES
|
||||||
sql/key_value_pair.cpp
|
sql/key_value_pair.cpp
|
||||||
sql/basic_condition.cpp
|
sql/basic_condition.cpp
|
||||||
sql/connection.cpp
|
sql/connection.cpp
|
||||||
sql/connection_intermediates.cpp
|
sql/query_intermediates.cpp
|
||||||
sql/record.cpp
|
sql/record.cpp
|
||||||
sql/connection_info.cpp
|
sql/connection_info.cpp
|
||||||
sql/connection_impl.cpp)
|
sql/connection_impl.cpp
|
||||||
|
sql/session.cpp)
|
||||||
|
|
||||||
set(SQL_HEADER
|
set(SQL_HEADER
|
||||||
../include/matador/sql/dialect.hpp
|
../include/matador/sql/dialect.hpp
|
||||||
|
|
@ -19,22 +20,27 @@ set(SQL_HEADER
|
||||||
../include/matador/sql/basic_condition.hpp
|
../include/matador/sql/basic_condition.hpp
|
||||||
../include/matador/sql/condition.hpp
|
../include/matador/sql/condition.hpp
|
||||||
../include/matador/sql/connection.hpp
|
../include/matador/sql/connection.hpp
|
||||||
../include/matador/sql/connection_intermediates.hpp
|
../include/matador/sql/query_intermediates.hpp
|
||||||
../include/matador/sql/result.hpp
|
../include/matador/sql/result.hpp
|
||||||
../include/matador/sql/record.hpp
|
../include/matador/sql/record.hpp
|
||||||
../include/matador/sql/query_result.hpp
|
../include/matador/sql/query_result.hpp
|
||||||
../include/matador/sql/connection_impl.hpp
|
../include/matador/sql/connection_impl.hpp
|
||||||
../include/matador/sql/connection_info.hpp)
|
../include/matador/sql/connection_info.hpp
|
||||||
|
../include/matador/sql/connection_pool.hpp
|
||||||
|
../include/matador/sql/session.hpp)
|
||||||
|
|
||||||
set(UTILS_HEADER
|
set(UTILS_HEADER
|
||||||
../include/matador/utils/field_attributes.hpp
|
../include/matador/utils/field_attributes.hpp
|
||||||
../include/matador/utils/string.hpp
|
../include/matador/utils/string.hpp
|
||||||
../include/matador/utils/constraints.hpp)
|
../include/matador/utils/constraints.hpp
|
||||||
|
../include/matador/utils/library.hpp)
|
||||||
|
|
||||||
set(UTILS_SOURCES
|
set(UTILS_SOURCES
|
||||||
utils/field_attributes.cpp
|
utils/field_attributes.cpp
|
||||||
utils/string.cpp
|
utils/string.cpp
|
||||||
sql/condition.cpp)
|
sql/condition.cpp
|
||||||
|
utils/library.cpp)
|
||||||
|
|
||||||
add_library(matador STATIC ${SQL_SOURCES} ${SQL_HEADER} ${UTILS_SOURCES} ${UTILS_HEADER})
|
add_library(matador STATIC ${SQL_SOURCES} ${SQL_HEADER} ${UTILS_SOURCES} ${UTILS_HEADER})
|
||||||
set_target_properties(matador PROPERTIES LINKER_LANGUAGE CXX)
|
target_include_directories(matador PUBLIC ${PROJECT_SOURCE_DIR}/include)
|
||||||
|
#set_target_properties(matador PROPERTIES LINKER_LANGUAGE CXX)
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,30 @@
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "matador/sql/connection.hpp"
|
#include "matador/sql/connection.hpp"
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
|
connection::connection(std::string dns)
|
||||||
|
: dns_(std::move(dns)) {}
|
||||||
|
|
||||||
connection::connection()
|
void connection::open()
|
||||||
: query_(dialect_) {}
|
|
||||||
|
|
||||||
query_create_intermediate connection::create()
|
|
||||||
{
|
{
|
||||||
return query_create_intermediate{*this, query_.create()};
|
is_open_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
query_drop_intermediate connection::drop()
|
void connection::close()
|
||||||
{
|
{
|
||||||
return query_drop_intermediate{*this, query_.drop()};
|
is_open_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
query_select_intermediate connection::select(std::initializer_list<std::string> column_names)
|
bool connection::is_open() const
|
||||||
{
|
{
|
||||||
return query_select_intermediate{*this, query_.select(column_names)};
|
return is_open_;
|
||||||
}
|
}
|
||||||
|
|
||||||
query_insert_intermediate connection::insert()
|
const std::string &connection::dns() const
|
||||||
{
|
{
|
||||||
return query_insert_intermediate{*this, query_.insert()};
|
return dns_;
|
||||||
}
|
|
||||||
|
|
||||||
query_update_intermediate connection::update(const std::string &table)
|
|
||||||
{
|
|
||||||
return query_update_intermediate{*this, query_.update(table)};
|
|
||||||
}
|
|
||||||
|
|
||||||
query_delete_intermediate connection::remove()
|
|
||||||
{
|
|
||||||
return query_delete_intermediate{*this, query_.remove()};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
query_result<record> connection::fetch(const std::string &sql)
|
query_result<record> connection::fetch(const std::string &sql)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#include "matador/sql/connection_intermediates.hpp"
|
#include "matador/sql/query_intermediates.hpp"
|
||||||
#include "matador/sql/connection.hpp"
|
#include "matador/sql/session.hpp"
|
||||||
#include "matador/sql/query_builder.hpp"
|
#include "matador/sql/query_builder.hpp"
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
connection &query_intermediate::db()
|
session &query_intermediate::db()
|
||||||
{
|
{
|
||||||
return db_;
|
return db_;
|
||||||
}
|
}
|
||||||
|
|
@ -23,7 +23,7 @@ record query_select_finish::fetch_one()
|
||||||
return db().fetch(query().compile()).begin();
|
return db().fetch(query().compile()).begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
query_intermediate::query_intermediate(connection &db, query_builder &query)
|
query_intermediate::query_intermediate(session &db, query_builder &query)
|
||||||
: db_(db), query_(query) {}
|
: db_(db), query_(query) {}
|
||||||
|
|
||||||
query_offset_intermediate query_order_direction_intermediate::offset(size_t offset)
|
query_offset_intermediate query_order_direction_intermediate::offset(size_t offset)
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
#include "matador/sql/session.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace matador::sql {
|
||||||
|
|
||||||
|
session::session(connection_pool<connection> &pool)
|
||||||
|
: pool_(pool)
|
||||||
|
, query_(dialect_) {}
|
||||||
|
|
||||||
|
query_create_intermediate session::create()
|
||||||
|
{
|
||||||
|
return query_create_intermediate{*this, query_.create()};
|
||||||
|
}
|
||||||
|
|
||||||
|
query_drop_intermediate session::drop()
|
||||||
|
{
|
||||||
|
return query_drop_intermediate{*this, query_.drop()};
|
||||||
|
}
|
||||||
|
|
||||||
|
query_select_intermediate session::select(std::initializer_list<std::string> column_names)
|
||||||
|
{
|
||||||
|
return query_select_intermediate{*this, query_.select(column_names)};
|
||||||
|
}
|
||||||
|
|
||||||
|
query_insert_intermediate session::insert()
|
||||||
|
{
|
||||||
|
return query_insert_intermediate{*this, query_.insert()};
|
||||||
|
}
|
||||||
|
|
||||||
|
query_update_intermediate session::update(const std::string &table)
|
||||||
|
{
|
||||||
|
return query_update_intermediate{*this, query_.update(table)};
|
||||||
|
}
|
||||||
|
|
||||||
|
query_delete_intermediate session::remove()
|
||||||
|
{
|
||||||
|
return query_delete_intermediate{*this, query_.remove()};
|
||||||
|
}
|
||||||
|
|
||||||
|
query_result<record> session::fetch(const std::string &sql) {
|
||||||
|
auto c = pool_.acquire();
|
||||||
|
if (!c.valid()) {
|
||||||
|
throw std::logic_error("no database connection available");
|
||||||
|
}
|
||||||
|
return c->fetch(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<size_t, std::string> session::execute(const std::string &sql) {
|
||||||
|
auto c = pool_.acquire();
|
||||||
|
if (!c.valid()) {
|
||||||
|
throw std::logic_error("no database connection available");
|
||||||
|
}
|
||||||
|
return c->execute(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
#include "matador/utils/library.hpp"
|
||||||
|
|
||||||
|
namespace matador::utils {
|
||||||
|
|
||||||
|
library::library(std::string lib)
|
||||||
|
: lib_(std::move(lib))
|
||||||
|
{}
|
||||||
|
|
||||||
|
library::~library()
|
||||||
|
{
|
||||||
|
unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool library::load()
|
||||||
|
{
|
||||||
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
|
handle_ = LoadLibrary((lib_ + ".dll").c_str());
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
handle_ = dlopen(std::string("lib" + lib_ + ".dylib").c_str(), RTLD_LAZY);
|
||||||
|
#else
|
||||||
|
handle_ = dlopen(std::string("./lib" + lib_ + ".so").c_str(), RTLD_LAZY);
|
||||||
|
#endif
|
||||||
|
if (!handle_) {
|
||||||
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
|
DWORD errorMessageID = ::GetLastError();
|
||||||
|
#else
|
||||||
|
// TODO: handle win32 and linux error
|
||||||
|
fprintf(stdout, "dlopen error: %s", dlerror());
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool library::load(const std::string &lib)
|
||||||
|
{
|
||||||
|
if (handle_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
lib_ = lib;
|
||||||
|
return load();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool library::unload()
|
||||||
|
{
|
||||||
|
bool ret(true);
|
||||||
|
if (handle_) {
|
||||||
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
|
ret = FreeLibrary(handle_) == TRUE;
|
||||||
|
#else
|
||||||
|
ret = dlclose(handle_) == 0;
|
||||||
|
#endif
|
||||||
|
if (!ret) {
|
||||||
|
} else {
|
||||||
|
handle_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
func_ptr library::function(const std::string &f) const
|
||||||
|
{
|
||||||
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
|
return GetProcAddress(handle_, f.c_str());
|
||||||
|
#else
|
||||||
|
return dlsym(handle_, f.c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,9 @@ FetchContent_Declare(
|
||||||
FetchContent_MakeAvailable(Catch2)
|
FetchContent_MakeAvailable(Catch2)
|
||||||
|
|
||||||
add_executable(tests builder.cpp
|
add_executable(tests builder.cpp
|
||||||
connection.cpp
|
session.cpp
|
||||||
record.cpp)
|
record.cpp
|
||||||
|
connection_pool.cpp
|
||||||
|
query.cpp)
|
||||||
target_link_libraries(tests PRIVATE Catch2::Catch2WithMain matador)
|
target_link_libraries(tests PRIVATE Catch2::Catch2WithMain matador)
|
||||||
target_include_directories(tests PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>/include)
|
target_include_directories(tests PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>/include)
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
#include <matador/sql/connection.hpp>
|
||||||
|
#include <matador/sql/connection_pool.hpp>
|
||||||
|
|
||||||
|
using namespace matador::sql;
|
||||||
|
|
||||||
|
TEST_CASE("Create connection pool", "[connection pool]") {
|
||||||
|
using pool_t = connection_pool<connection>;
|
||||||
|
|
||||||
|
pool_t pool("db", 4);
|
||||||
|
|
||||||
|
REQUIRE(pool.size() == 4);
|
||||||
|
REQUIRE(pool.idle() == 4);
|
||||||
|
REQUIRE(pool.inuse() == 0);
|
||||||
|
|
||||||
|
auto ptr = pool.acquire();
|
||||||
|
REQUIRE(ptr.valid());
|
||||||
|
REQUIRE(ptr->is_open());
|
||||||
|
REQUIRE(!ptr->dns().empty());
|
||||||
|
|
||||||
|
REQUIRE(pool.idle() == 3);
|
||||||
|
REQUIRE(pool.inuse() == 1);
|
||||||
|
|
||||||
|
pool.release(ptr);
|
||||||
|
REQUIRE(!ptr.valid());
|
||||||
|
REQUIRE(pool.idle() == 4);
|
||||||
|
REQUIRE(pool.inuse() == 0);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto ptr2 = pool.acquire();
|
||||||
|
REQUIRE(ptr2.valid());
|
||||||
|
REQUIRE(ptr2->is_open());
|
||||||
|
REQUIRE(!ptr2->dns().empty());
|
||||||
|
|
||||||
|
REQUIRE(pool.idle() == 3);
|
||||||
|
REQUIRE(pool.inuse() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(pool.idle() == 4);
|
||||||
|
REQUIRE(pool.inuse() == 0);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include "catch2/generators/catch_generators.hpp"
|
||||||
|
|
||||||
|
TEST_CASE("Query test", "[query]") {
|
||||||
|
auto dns = GENERATE(as<std::string>{}, "mssql", "sqlite", "postgres" );
|
||||||
|
|
||||||
|
INFO(dns);
|
||||||
|
REQUIRE(!dns.empty());
|
||||||
|
}
|
||||||
|
|
@ -2,14 +2,15 @@
|
||||||
|
|
||||||
#include <matador/sql/column.hpp>
|
#include <matador/sql/column.hpp>
|
||||||
#include <matador/sql/condition.hpp>
|
#include <matador/sql/condition.hpp>
|
||||||
#include <matador/sql/connection.hpp>
|
#include <matador/sql/session.hpp>
|
||||||
|
|
||||||
using namespace matador::sql;
|
using namespace matador::sql;
|
||||||
|
|
||||||
TEST_CASE("Execute create table statement", "[connection]") {
|
TEST_CASE("Execute create table statement", "[connection]") {
|
||||||
connection c;
|
connection_pool<connection> pool("dns", 4);
|
||||||
|
session s(pool);
|
||||||
|
|
||||||
const auto res = c.create()
|
const auto res = s.create()
|
||||||
.table("person", {
|
.table("person", {
|
||||||
make_pk_column<unsigned long>("id"),
|
make_pk_column<unsigned long>("id"),
|
||||||
make_column<std::string>("name", 255),
|
make_column<std::string>("name", 255),
|
||||||
|
|
@ -21,9 +22,10 @@ TEST_CASE("Execute create table statement", "[connection]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execute drop table statement", "[connection]") {
|
TEST_CASE("Execute drop table statement", "[connection]") {
|
||||||
connection c;
|
connection_pool<connection> pool("dns", 4);
|
||||||
|
session s(pool);
|
||||||
|
|
||||||
const auto res = c.drop()
|
const auto res = s.drop()
|
||||||
.table("person")
|
.table("person")
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
|
|
@ -31,9 +33,10 @@ TEST_CASE("Execute drop table statement", "[connection]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execute select statement with where clause", "[connection]") {
|
TEST_CASE("Execute select statement with where clause", "[connection]") {
|
||||||
connection c;
|
connection_pool<connection> pool("dns", 4);
|
||||||
|
session s(pool);
|
||||||
|
|
||||||
auto res = c.select({"id", "name", "color"})
|
auto res = s.select({"id", "name", "color"})
|
||||||
.from("person")
|
.from("person")
|
||||||
.where("id"_col == 8)
|
.where("id"_col == 8)
|
||||||
.fetch_all();
|
.fetch_all();
|
||||||
|
|
@ -42,9 +45,10 @@ TEST_CASE("Execute select statement with where clause", "[connection]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execute select statement with order by", "[connection]") {
|
TEST_CASE("Execute select statement with order by", "[connection]") {
|
||||||
connection c;
|
connection_pool<connection> pool("dns", 4);
|
||||||
|
session s(pool);
|
||||||
|
|
||||||
auto res = c.select({"id", "name", "color"})
|
auto res = s.select({"id", "name", "color"})
|
||||||
.from("person")
|
.from("person")
|
||||||
.where("id"_col == 8)
|
.where("id"_col == 8)
|
||||||
.order_by("name").desc()
|
.order_by("name").desc()
|
||||||
|
|
@ -54,9 +58,10 @@ TEST_CASE("Execute select statement with order by", "[connection]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execute select statement with group by and order by", "[connection]") {
|
TEST_CASE("Execute select statement with group by and order by", "[connection]") {
|
||||||
connection c;
|
connection_pool<connection> pool("dns", 4);
|
||||||
|
session s(pool);
|
||||||
|
|
||||||
auto res = c.select({"id", "name", "color"})
|
auto res = s.select({"id", "name", "color"})
|
||||||
.from("person")
|
.from("person")
|
||||||
.where("id"_col == 8)
|
.where("id"_col == 8)
|
||||||
.group_by("color")
|
.group_by("color")
|
||||||
|
|
@ -67,9 +72,10 @@ TEST_CASE("Execute select statement with group by and order by", "[connection]")
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execute insert statement", "[connection]") {
|
TEST_CASE("Execute insert statement", "[connection]") {
|
||||||
connection c;
|
connection_pool<connection> pool("dns", 4);
|
||||||
|
session s(pool);
|
||||||
|
|
||||||
auto res = c.insert()
|
auto res = s.insert()
|
||||||
.into("person", {"id", "name", "color"})
|
.into("person", {"id", "name", "color"})
|
||||||
.values({7, "george", "green"})
|
.values({7, "george", "green"})
|
||||||
.execute();
|
.execute();
|
||||||
|
|
@ -78,9 +84,10 @@ TEST_CASE("Execute insert statement", "[connection]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execute update statement", "[connection]") {
|
TEST_CASE("Execute update statement", "[connection]") {
|
||||||
connection c;
|
connection_pool<connection> pool("dns", 4);
|
||||||
|
session s(pool);
|
||||||
|
|
||||||
auto res = c.update("person")
|
auto res = s.update("person")
|
||||||
.set({
|
.set({
|
||||||
{"name", "george"},
|
{"name", "george"},
|
||||||
{"color", "green"}
|
{"color", "green"}
|
||||||
|
|
@ -92,9 +99,10 @@ TEST_CASE("Execute update statement", "[connection]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execute delete statement", "[connection]") {
|
TEST_CASE("Execute delete statement", "[connection]") {
|
||||||
connection c;
|
connection_pool<connection> pool("dns", 4);
|
||||||
|
session s(pool);
|
||||||
|
|
||||||
auto res = c.remove()
|
auto res = s.remove()
|
||||||
.from("person", "p")
|
.from("person", "p")
|
||||||
.where("id"_col == 9)
|
.where("id"_col == 9)
|
||||||
.execute();
|
.execute();
|
||||||
Loading…
Reference in New Issue