PreVerify/lib/qtl/include/qtl_common.hpp

1458 lines
40 KiB
C++
Raw Normal View History

2024-09-09 19:18:28 +08:00
#ifndef _QTL_COMMON_H_
#define _QTL_COMMON_H_
#if __cplusplus<201103L && _MSC_VER<1800
#error QTL need C++11 compiler
#endif //C++11
#if _MSC_VER>=1800 && _MSC_VER<1900
#define NOEXCEPT throw()
#else
#define NOEXCEPT noexcept
#endif //NOEXCEPT
#include <stdint.h>
#include <string.h>
#include <type_traits>
#include <tuple>
#include <memory>
#include <string>
#include <vector>
#include <functional>
#include <algorithm>
#include "apply_tuple.h"
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
#define _QTL_ENABLE_CPP17
#include <optional>
#include <any>
#endif // C++17
namespace qtl
{
struct null { };
struct blob_data
{
void* data;
size_t size;
blob_data() : data(NULL), size(0) { }
blob_data(void* d, size_t n) : data(d), size(n) { }
};
struct const_blob_data
{
const void* data;
size_t size;
const_blob_data() : data(NULL), size(0) { }
const_blob_data(const void* d, size_t n) : data(d), size(n) { }
};
const size_t blob_buffer_size=64*1024;
inline std::string& trim_string(std::string& str, const char* target)
{
str.erase(0, str.find_first_not_of(target));
str.erase(str.find_last_not_of(target)+1);
return str;
}
template<typename T>
struct indicator
{
typedef T data_type;
data_type data;
size_t length;
bool is_null;
bool is_truncated;
indicator()
: is_null(false), is_truncated(false), length(0) { }
explicit indicator(const data_type& src)
: is_null(false), is_truncated(false), length(0), data(src) { }
explicit indicator(data_type&& src)
: is_null(false), is_truncated(false), length(0), data(std::move(src)) { }
operator bool() const { return is_null; }
operator data_type&() { return data; }
operator const data_type&() const { return data; }
};
template<typename StringT>
struct bind_string_helper
{
typedef StringT string_type;
typedef typename string_type::value_type char_type;
bind_string_helper(string_type&& value) : m_value(std::forward<string_type>(value)) { }
bind_string_helper(const bind_string_helper& src)
: m_value(std::forward<StringT>(src.m_value))
{
}
bind_string_helper(bind_string_helper&& src)
: m_value(std::forward<StringT>(src.m_value))
{
}
bind_string_helper& operator=(const bind_string_helper& src)
{
if (this != &src)
{
m_value = std::forward<StringT>(src.m_value);
}
return *this;
}
bind_string_helper& operator=(bind_string_helper&& src)
{
if (this != &src)
{
m_value = std::forward<StringT>(src.m_value);
}
return *this;
}
void clear() { m_value.clear(); }
char_type* alloc(size_t n) { m_value.resize(n); return (char_type*)m_value.data(); }
void truncate(size_t n) { m_value.resize(n); }
void assign(const char_type* str, size_t n) { m_value.assign(str, n); }
const char_type* data() const { return m_value.data(); }
size_t size() const { return m_value.size(); }
private:
string_type&& m_value;
};
template<typename StringT>
inline bind_string_helper<typename std::decay<StringT>::type> bind_string(StringT&& value)
{
typedef typename std::decay<StringT>::type string_type;
return bind_string_helper<string_type>(std::forward<string_type>(value));
}
template<typename Command>
inline void bind_param(Command& command, size_t index, const std::string& param)
{
command.bind_param(index, param.data(), param.size());
}
template<typename Command>
inline void bind_param(Command& command, size_t index, std::istream& param)
{
command.bind_param(index, param);
}
template<typename Command, typename T>
inline void bind_param(Command& command, size_t index, const T& param)
{
command.bind_param(index, param);
}
#ifdef _QTL_ENABLE_CPP17
template<typename Command, typename T>
inline void bind_param(Command& command, size_t index, const std::optional<T>& param)
{
if(param)
command.bind_param(index, *param);
else
command.bind_param(index, nullptr);
}
#endif // C++17
// The order of the overloaded functions 'bind_field' is very important
// The version with the most generic parameters is at the end
template<typename Command, size_t N>
inline void bind_field(Command& command, size_t index, char (&value)[N])
{
command.bind_field(index, value, N);
}
template<typename Command, size_t N>
inline void bind_field(Command& command, size_t index, wchar_t (&value)[N])
{
command.bind_field(index, value, N);
}
template<typename Command>
inline void bind_field(Command& command, size_t index, char* value, size_t length)
{
command.bind_field(index, value, length);
}
template<typename Command>
inline void bind_field(Command& command, size_t index, wchar_t* value, size_t length)
{
command.bind_field(index, value, length);
}
template<typename Command>
inline void bind_field(Command& command, size_t index, std::string&& value)
{
command.bind_field(index, bind_string(std::forward<std::string>(value)));
}
template<typename Command>
inline void bind_field(Command& command, size_t index, std::wstring&& value)
{
command.bind_field(index, bind_string(std::forward<std::wstring>(value)));
}
template<typename Command>
inline void bind_field(Command& command, size_t index, std::vector<char>&& value)
{
command.bind_field(index, bind_string(std::forward<std::vector<char>>(value)));
}
template<typename Command>
inline void bind_field(Command& command, size_t index, std::vector<wchar_t>&& value)
{
command.bind_field(index, bind_string(std::forward<std::vector<wchar_t>>(value)));
}
template<typename Command, typename T, typename=typename std::enable_if<!std::is_reference<T>::value>::type>
inline void bind_field(Command& command, size_t index, T&& value)
{
command.bind_field(index, std::forward<T>(value));
}
template<typename Command, typename T>
inline void bind_field(Command& command, size_t index, T& value)
{
bind_field(command, index, std::forward<T>(value));
}
template<typename Command, typename T, typename=typename std::enable_if<!std::is_reference<T>::value>::type>
inline void bind_field(Command& command, const char* name, T&& value)
{
size_t index=command.find_field(name);
if(index==-1)
value=T();
else
command.bind_field(index, std::forward<T>(value));
}
template<typename Command, typename T>
inline void bind_field(Command& command, const char* name, T& value)
{
size_t index=command.find_field(name);
if(index==-1)
value=T();
else
bind_field(command, index, std::forward<T>(value));
}
template<typename Command>
inline void bind_field(Command& command, const char* name, char* value, size_t length)
{
size_t index=command.find_field(name);
if (index == -1)
{
if (length > 0) value[0] = '\0';
}
else
command.bind_field(index, value, length);
}
template<typename Command>
inline void bind_field(Command& command, const char* name, wchar_t* value, size_t length)
{
size_t index=command.find_field(name);
if (index == -1)
{
if (length > 0) value[0] = '\0';
}
else
command.bind_field(index, value, length);
}
template<typename Command, typename T>
inline void bind_field(Command& command, const char* name, std::reference_wrapper<T>&& value)
{
return bind_field(command, value.get());
}
#ifdef _QTL_ENABLE_CPP17
template<typename Command, typename T>
inline void bind_field(Command& command, size_t index, std::optional<T>& value)
{
value.emplace();
command.bind_field(index, std::forward<T>(value));
}
template<typename Command, typename T>
inline void bind_field(Command& command, const char* name, std::optional<T>& value)
{
size_t index = command.find_field(name);
if (index == -1)
value.reset();
else
bind_field(command, index, value);
}
#endif // C++17
template<typename Command, typename T>
inline size_t bind_fields(Command& command, size_t index, T&& value)
{
bind_field(command, index, std::forward<T>(value));
return index+1;
}
template<typename Command, typename T, typename... Other>
inline size_t bind_fields(Command& command, size_t start, T&& value, Other&&... other)
{
bind_field(command, start, std::forward<T>(value));
return bind_fields(command, start+1, std::forward<Other>(other)...);
}
template<typename Command, typename... Fields>
inline size_t bind_fields(Command& command, Fields&&... fields)
{
return bind_fields(command, (size_t)0, std::forward<Fields>(fields)...);
}
namespace detail
{
template<typename F, typename T>
struct apply_impl
{
private:
#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L
typedef typename std::invoke_result<F, T>::type raw_result_type;
#else
typedef typename std::result_of<F(T)>::type raw_result_type;
#endif
template<typename Ret, bool>
struct impl {};
template<typename Ret>
struct impl<Ret, true>
{
typedef bool result_type;
result_type operator()(F&& f, T&& v)
{
f(std::forward<T>(v));
return true;
}
};
template<typename Ret>
struct impl<Ret, false>
{
typedef Ret result_type;
result_type operator()(F&& f, T&& v)
{
return f(std::forward<T>(v));
}
};
public:
typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
result_type operator()(F&& f, T&& v)
{
return impl<raw_result_type, std::is_void<raw_result_type>::value>()(std::forward<F>(f), std::forward<T>(v));
}
};
template<typename F, typename... Types>
struct apply_impl<F, std::tuple<Types...>>
{
private:
typedef typename std::remove_reference<F>::type fun_type;
typedef std::tuple<Types...> arg_type;
#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L
typedef typename std::invoke_result<F, Types...>::type raw_result_type;
#else
typedef typename std::result_of<F(Types...)>::type raw_result_type;
#endif
template<typename Ret, bool>
struct impl {};
template<typename Ret>
struct impl<Ret, true>
{
typedef bool result_type;
result_type operator()(F&& f, arg_type&& v)
{
qtl::detail::apply_tuple(std::forward<F>(f), std::forward<arg_type>(v));
return true;
}
};
template<typename Ret>
struct impl<Ret, false>
{
typedef Ret result_type;
result_type operator()(F&& f, arg_type&& v)
{
return qtl::detail::apply_tuple(std::forward<F>(f), std::forward<arg_type>(v));
}
};
public:
typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
result_type operator()(F&& f, arg_type&& v)
{
return impl<raw_result_type, std::is_void<raw_result_type>::value>()(std::forward<F>(f), std::forward<arg_type>(v));
}
};
template<typename Type, typename R>
struct apply_impl<R (Type::*)(), Type>
{
private:
typedef R (Type::*fun_type)();
typedef R raw_result_type;
template<typename Ret, bool>
struct impl {};
template<typename Ret>
struct impl<Ret, true>
{
typedef bool result_type;
result_type operator()(fun_type f, Type&& v)
{
(v.*f)();
return true;
}
};
template<typename Ret>
struct impl<Ret, false>
{
typedef Ret result_type;
result_type operator()(fun_type f, Type&& v)
{
return (v.*f)();
}
};
public:
typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
result_type operator()(R (Type::*f)(), Type&& v)
{
return impl<raw_result_type, std::is_void<raw_result_type>::value>()(f, std::forward<Type>(v));
}
};
template<typename Type, typename R>
struct apply_impl<R (Type::*)() const, Type>
{
private:
typedef R (Type::*fun_type)() const;
typedef R raw_result_type;
template<typename Ret, bool>
struct impl {};
template<typename Ret>
struct impl<Ret, true>
{
typedef bool result_type;
result_type operator()(fun_type f, Type&& v)
{
(v.*f)();
return true;
}
};
template<typename Ret>
struct impl<Ret, false>
{
typedef Ret result_type;
result_type operator()(fun_type f, Type&& v)
{
return (v.*f)();
}
};
public:
typedef typename impl<raw_result_type, std::is_void<raw_result_type>::value>::result_type result_type;
result_type operator()(fun_type f, Type&& v)
{
return impl<raw_result_type, std::is_void<raw_result_type>::value>()(f, std::forward<Type>(v));
}
};
template<typename F, typename T>
typename apply_impl<F, T>::result_type apply(F&& f, T&& v)
{
return apply_impl<F, T>()(std::forward<F>(f), std::forward<T>(v));
}
template<typename Command, size_t N, typename... Types>
struct bind_helper
{
public:
explicit bind_helper(Command& command) : m_command(command) { }
void operator()(const std::tuple<Types...>& params) const
{
bind_param(m_command, N-1, std::get<N-1>(params));
(bind_helper<Command, N-1, Types...>(m_command))(params);
}
void operator()(std::tuple<Types...>&& params) const
{
typedef typename std::remove_reference<typename std::tuple_element<N-1, tuple_type>::type>::type param_type;
bind_field(m_command, N-1, std::forward<param_type>(std::get<N-1>(std::forward<tuple_type>(params))));
(bind_helper<Command, N-1, Types...>(m_command))(std::forward<tuple_type>(params));
}
private:
typedef std::tuple<Types...> tuple_type;
Command& m_command;
};
template<typename Command, typename... Types>
struct bind_helper<Command, 1, Types...>
{
public:
explicit bind_helper(Command& command) : m_command(command) { }
void operator()(const std::tuple<Types...>& params) const
{
bind_param(m_command, 0, std::get<0>(params));
}
void operator()(std::tuple<Types...>&& params) const
{
typedef typename std::remove_reference<typename std::tuple_element<0, tuple_type>::type>::type param_type;
bind_field(m_command, static_cast<size_t>(0), std::forward<param_type>(std::get<0>(std::forward<tuple_type>(params))));
}
private:
typedef std::tuple<Types...> tuple_type;
Command& m_command;
};
template<typename Command, typename... Types>
struct bind_helper<Command, 0, Types...>
{
public:
explicit bind_helper(Command& command) { }
void operator()(const std::tuple<Types...>& params) const
{
}
void operator()(std::tuple<Types...>&& params) const
{
}
};
#define QTL_ARGS_TUPLE(Arg, Others) \
typename std::tuple<typename std::decay<Arg>::type, typename std::decay<Others>::type...>
template<typename Ret, typename Arg>
inline typename std::decay<Arg>::type make_values(Ret (*)(Arg))
{
return typename std::decay<Arg>::type();
};
template<typename Ret, typename Arg, typename... Others>
inline auto make_values(Ret (*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others)
{
return QTL_ARGS_TUPLE(Arg, Others)();
};
template<typename Type, typename Ret>
inline Type make_values(Ret (Type::*)())
{
return Type();
};
template<typename Type, typename Ret>
inline Type make_values(Ret (Type::*)() const)
{
return Type();
};
template<typename Type, typename Ret, typename... Args>
inline auto make_values(Ret (Type::*)(Args...)) -> QTL_ARGS_TUPLE(Type, Args)
{
return QTL_ARGS_TUPLE(Type, Args)();
};
template<typename Type, typename Ret, typename... Args>
inline auto make_values(Ret (Type::*)(Args...) const) -> QTL_ARGS_TUPLE(Type, Args)
{
return QTL_ARGS_TUPLE(Type, Args)();
};
template<typename Type, typename Ret, typename Arg>
inline typename std::decay<Arg>::type make_values_noclass(Ret (Type::*)(Arg))
{
return typename std::decay<Arg>::type();
};
template<typename Type, typename Ret, typename Arg>
inline typename std::decay<Arg>::type make_values_noclass(Ret (Type::*)(Arg) const)
{
return typename std::decay<Arg>::type();
};
template<typename Type, typename Ret, typename Arg, typename... Others>
inline auto make_values_noclass(Ret (Type::*)(Arg, Others...)) -> QTL_ARGS_TUPLE(Arg, Others)
{
return QTL_ARGS_TUPLE(Arg, Others)();
};
template<typename Type, typename Ret, typename Arg, typename... Others>
inline auto make_values_noclass(Ret (Type::*)(Arg, Others...) const) -> QTL_ARGS_TUPLE(Arg, Others)
{
return QTL_ARGS_TUPLE(Arg, Others)();
};
template<typename Functor, typename=typename std::enable_if<std::is_member_function_pointer<decltype(&Functor::operator())>::value>::type>
inline auto make_values(const Functor&)
-> decltype(make_values_noclass(&Functor::operator()))
{
return make_values_noclass(&Functor::operator());
}
template<typename Command, typename ValueProc>
inline void fetch_command(Command& command, ValueProc&& proc)
{
auto values=make_values(proc);
typedef decltype(values) values_type;
while(command.fetch(std::forward<values_type>(values)))
{
if(!apply(std::forward<ValueProc>(proc), std::forward<values_type>(values)))
break;
}
}
template<typename Command, typename ValueProc, typename... OtherProc>
inline void fetch_command(Command& command, ValueProc&& proc, OtherProc&&... other)
{
fetch_command(command, std::forward<ValueProc>(proc));
if(command.next_result())
{
fetch_command(command, std::forward<OtherProc>(other)...);
}
}
}
template<typename Command, typename T>
struct params_binder
{
enum { size = 1 };
inline void operator()(Command& command, const T& param) const
{
qtl::bind_param(command, 0, param);
}
};
template<typename Command, typename... Types>
struct params_binder<Command, std::tuple<Types...>>
{
enum { size = sizeof...(Types) };
void operator()(Command& command, const std::tuple<Types...>& params) const
{
(detail::bind_helper<Command, std::tuple_size<std::tuple<Types...>>::value, Types...>(command))(params);
}
};
template<typename Command, typename Type1, typename Type2>
struct params_binder<Command, std::pair<Type1, Type2>>
{
enum { size = 2 };
void operator()(Command& command, std::pair<Type1, Type2>&& values) const
{
qtl::bind_param(command, 0, std::forward<Type1>(values.first));
qtl::bind_param(command, 1, std::forward<Type2>(values.second));
}
};
template<typename Command, typename T>
inline void bind_params(Command& command, const T& param)
{
params_binder<Command, T> binder;
binder(command, param);
}
template<typename Command, typename T>
struct record_binder
{
inline void operator()(Command& command, T&& value) const
{
bind_field(command, static_cast<size_t>(0), std::forward<typename std::remove_reference<T>::type>(value));
}
};
template<typename Command, typename T>
struct record_binder<Command, std::reference_wrapper<T>>
{
inline void operator()(Command& command, std::reference_wrapper<T>&& value) const
{
bind_field(command, static_cast<size_t>(0), std::forward<typename std::remove_reference<T>::type>(value.get()));
}
};
template<typename Command, typename... Types>
struct record_binder<Command, std::tuple<Types...>>
{
void operator()(Command& command, std::tuple<Types...>&& values) const
{
(detail::bind_helper<Command, std::tuple_size<std::tuple<Types...>>::value, Types...>(command))
(std::forward<std::tuple<Types...>>(values));
}
};
template<typename Command, typename Type1, typename Type2>
struct record_binder<Command, std::pair<Type1, Type2>>
{
void operator()(Command& command, std::pair<Type1, Type2>&& values) const
{
bind_field(command, static_cast<size_t>(0), std::forward<Type1>(values.first));
bind_field(command, static_cast<size_t>(1), std::forward<Type2>(values.second));
}
};
template<typename T, typename Tag>
struct record_with_tag : public T
{
};
template<typename T, typename Pred>
struct custom_binder_type : public T
{
typedef T value_type;
explicit custom_binder_type(Pred pred) : m_pred(pred) { }
custom_binder_type(value_type&& v, Pred pred)
: value_type(std::forward<value_type>(v)), m_pred(pred)
{
}
template<typename... Args>
custom_binder_type(Pred pred, Args&&... args)
: value_type(std::forward<Args>(args)...), m_pred(pred)
{
}
template<typename Command>
void bind(Command& command)
{
m_pred(std::forward<T>(*this), command); // Pred maybe member function
}
private:
Pred m_pred;
};
template<typename T, typename Pred>
struct custom_binder_type<std::reference_wrapper<T>, Pred> : public std::reference_wrapper<T>
{
typedef std::reference_wrapper<T> value_type;
explicit custom_binder_type(Pred pred) : m_pred(pred) { }
custom_binder_type(value_type&& v, Pred pred)
: value_type(std::forward<value_type>(v)), m_pred(pred)
{
}
template<typename... Args>
custom_binder_type(Pred pred, Args&&... args)
: T(std::forward<Args>(args)...), m_pred(pred)
{
}
template<typename Command>
void bind(Command& command)
{
m_pred(std::forward<T>(*this), command); // Pred maybe member function
}
private:
Pred m_pred;
};
template<typename T, typename Pred>
inline custom_binder_type<T, Pred> custom_bind(T&& v, Pred pred)
{
return custom_binder_type<T, Pred>(std::forward<T>(v), pred);
}
template<typename Command, typename T, typename Pred>
struct record_binder<Command, custom_binder_type<T, Pred>>
{
void operator()(Command& command, custom_binder_type<T, Pred>&& values) const
{
values.bind(command);
}
};
template<typename Command, typename T>
inline void bind_record(Command& command, T&& value)
{
record_binder<Command, T> binder;
binder(command, std::forward<T>(value));
}
template<typename Command, typename Record>
class query_iterator final
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = Record;
using difference_type = ptrdiff_t;
using pointer = Record*;
using reference = Record&;
explicit query_iterator(Command& command)
: m_command(command) { }
Record* operator->() const { return m_record.get(); }
Record& operator*() const { return *m_record; }
query_iterator& operator++()
{
if(!m_record)
m_record=std::make_shared<Record>();
if(m_record.use_count()==1)
{
if(!m_command.fetch(std::forward<Record>(*m_record)))
m_record.reset();
}
else
{
std::shared_ptr<Record> record=std::make_shared<Record>();
if(m_command.fetch(std::forward<Record>(*record)))
m_record=record;
else
m_record.reset();
}
return *this;
}
query_iterator operator++(int)
{
query_iterator temp=*this;
m_record=std::make_shared<Record>();
if(!m_command.fetch(std::forward<Record>(*m_record)))
m_record.reset();
return temp;
}
bool operator ==(const query_iterator& rhs)
{
return &this->m_command==&rhs.m_command &&
this->m_record==rhs.m_record;
}
bool operator !=(const query_iterator& rhs)
{
return !(*this==rhs);
}
private:
Command& m_command;
std::shared_ptr<Record> m_record;
};
template<typename Command, typename Record>
class query_result final
{
public:
typedef typename query_iterator<Command, Record>::value_type value_type;
typedef typename query_iterator<Command, Record>::pointer pointer;
typedef typename query_iterator<Command, Record>::reference reference;
typedef query_iterator<Command, Record> iterator;
explicit query_result(Command&& command) : m_command(std::move(command)) { }
query_result(query_result&& src) : m_command(std::move(src.m_command)) { }
query_result& operator=(query_result&& src)
{
if(this!=&src)
m_command=std::move(src.m_command);
return *this;
}
template<typename Params>
iterator begin(const Params& params)
{
query_iterator<Command, Record> it(m_command);
++it;
return it;
}
iterator begin()
{
return begin(std::make_tuple());
}
iterator end()
{
return query_iterator<Command, Record>(m_command);
}
private:
Command m_command;
};
template<typename T, class Command>
class base_database
{
public:
template<typename Params>
base_database& execute(const char* query_text, size_t text_length, const Params& params, uint64_t* affected=NULL)
{
T* pThis=static_cast<T*>(this);
Command command=pThis->open_command(query_text, text_length);
command.execute(params);
if(affected) *affected=command.affetced_rows();
command.close();
return *this;
}
template<typename Params>
base_database& execute(const char* query_text, const Params& params, uint64_t* affected=NULL)
{
return execute(query_text, strlen(query_text), params, affected);
}
template<typename Params>
base_database& execute(const std::string& query_text, const Params& params, uint64_t* affected=NULL)
{
return execute(query_text.data(), query_text.length(), params, affected);
}
template<typename... Params>
base_database& execute_direct(const char* query_text, size_t text_length, uint64_t* affected, const Params&... params)
{
return execute(query_text, text_length, std::forward_as_tuple(params...), affected);
}
template<typename... Params>
base_database& execute_direct(const char* query_text, uint64_t* affected, const Params&... params)
{
return execute(query_text, std::forward_as_tuple(params...), affected);
}
template<typename... Params>
base_database& execute_direct(const std::string& query_text, uint64_t* affected, const Params&... params)
{
return execute(query_text, std::forward_as_tuple(params...), affected);
}
template<typename Params>
uint64_t insert(const char* query_text, size_t text_length, const Params& params)
{
uint64_t id=0;
T* pThis=static_cast<T*>(this);
Command command=pThis->open_command(query_text, text_length);
command.execute(params);
if(command.affetced_rows()>0)
id=command.insert_id();
return id;
}
template<typename Params>
uint64_t insert(const char* query_text, const Params& params)
{
return insert(query_text, strlen(query_text), params);
}
template<typename Params>
uint64_t insert(const std::string& query_text, const Params& params)
{
return insert(query_text.data(), query_text.length(), params);
}
template<typename... Params>
uint64_t insert_direct(const char* query_text, size_t text_length, const Params&... params)
{
return insert(query_text, text_length, std::forward_as_tuple(params...));
}
template<typename... Params>
uint64_t insert_direct(const char* query_text, const Params&... params)
{
return insert(query_text, strlen(query_text), std::forward_as_tuple(params...));
}
template<typename... Params>
uint64_t insert_direct(const std::string& query_text, const Params&... params)
{
return insert(query_text.data(), query_text.length(), std::forward_as_tuple(params...));
}
template<typename Record, typename Params>
query_result<Command, Record> result(const char* query_text, size_t text_length, const Params& params)
{
T* pThis=static_cast<T*>(this);
Command command=pThis->open_command(query_text, text_length);
command.execute(params);
return query_result<Command, Record>(std::move(command));
}
template<typename Record, typename Params>
query_result<Command, Record> result(const char* query_text, const Params& params)
{
return result<Record, Params>(query_text, strlen(query_text), params);
}
template<typename Record, typename Params>
query_result<Command, Record> result(const std::string& query_text, const Params& params)
{
return result<Record, Params>(query_text.data(), query_text.length(), params);
}
template<typename Record>
query_result<Command, Record> result(const char* query_text, size_t text_length)
{
return result<Record>(query_text, text_length, std::make_tuple());
}
template<typename Record>
query_result<Command, Record> result(const char* query_text)
{
return result<Record>(query_text, strlen(query_text), std::make_tuple());
}
template<typename Record>
query_result<Command, Record> result(const std::string& query_text)
{
return result<Record>(query_text.data(), query_text.length(), std::make_tuple());
}
template<typename Params, typename Values, typename ValueProc>
base_database& query_explicit(const char* query_text, size_t text_length, const Params& params, Values&& values, ValueProc&& proc)
{
T* pThis=static_cast<T*>(this);
Command command=pThis->open_command(query_text, text_length);
command.execute(params);
while(command.fetch(std::forward<Values>(values)))
{
if(!detail::apply(std::forward<ValueProc>(proc), std::forward<Values>(values))) break;
}
command.close();
return *this;
}
template<typename Params, typename Values, typename ValueProc>
base_database& query_explicit(const char* query_text, const Params& params, Values&& values, ValueProc&& proc)
{
return query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), std::forward<ValueProc>(proc));
}
template<typename Params, typename Values, typename ValueProc>
base_database& query_explicit(const std::string& query_text, const Params& params, Values&& values, ValueProc&& proc)
{
return query_explicit(query_text.data(), query_text.size(), params, std::forward<Values>(values), std::forward<ValueProc>(proc));
}
template<typename Values, typename ValueProc>
base_database& query_explicit(const char* query_text, size_t text_length, Values&& values, ValueProc&& proc)
{
return query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc));
}
template<typename Values, typename ValueProc>
base_database& query_explicit(const char* query_text, Values&& values, ValueProc&& proc)
{
return query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc));
}
template<typename Values, typename ValueProc>
base_database& query_explicit(const std::string& query_text, Values&& values, ValueProc&& proc)
{
return query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), std::forward<ValueProc>(proc));
}
template<typename Params, typename ValueProc>
base_database& query(const char* query_text, size_t text_length, const Params& params, ValueProc&& proc)
{
return query_explicit(query_text, text_length, params, detail::make_values(proc), std::forward<ValueProc>(proc));
}
template<typename Params, typename ValueProc>
base_database& query(const char* query_text, const Params& params, ValueProc&& proc)
{
return query_explicit(query_text, params, detail::make_values(proc), std::forward<ValueProc>(proc));
}
template<typename Params, typename ValueProc>
base_database& query(const std::string& query_text, const Params& params, ValueProc&& proc)
{
return query_explicit(query_text, params, detail::make_values(proc), std::forward<ValueProc>(proc));
}
template<typename ValueProc>
base_database& query(const char* query_text, size_t text_length, ValueProc&& proc)
{
return query_explicit(query_text, text_length, detail::make_values(proc), std::forward<ValueProc>(proc));
}
template<typename ValueProc>
base_database& query(const char* query_text, ValueProc&& proc)
{
return query_explicit(query_text, detail::make_values(proc), std::forward<ValueProc>(proc));
}
template<typename ValueProc>
base_database& query(const std::string& query_text, ValueProc&& proc)
{
return query_explicit(query_text, detail::make_values(proc), std::forward<ValueProc>(proc));
}
template<typename Params, typename... ValueProc>
base_database& query_multi_with_params(const char* query_text, size_t text_length, const Params& params, ValueProc&&... proc)
{
T* pThis=static_cast<T*>(this);
Command command=pThis->open_command(query_text, text_length);
command.execute(params);
detail::fetch_command(command, std::forward<ValueProc>(proc)...);
command.close();
return *this;
}
template<typename Params, typename... ValueProc>
base_database& query_multi_with_params(const char* query_text, const Params& params, ValueProc&&... proc)
{
return query_multi_with_params(query_text, strlen(query_text), params, std::forward<ValueProc>(proc)...);
}
template<typename Params, typename... ValueProc>
base_database& query_multi_with_params(const std::string& query_text, const Params& params, ValueProc&&... proc)
{
return query_multi_with_params(query_text.data(), query_text.size(), params, std::forward<ValueProc>(proc)...);
}
template<typename... ValueProc>
base_database& query_multi(const char* query_text, size_t text_length, ValueProc&&... proc)
{
return query_multi_with_params<std::tuple<>, ValueProc...>(query_text, text_length, std::make_tuple(), std::forward<ValueProc>(proc)...);
}
template<typename... ValueProc>
base_database& query_multi(const char* query_text, ValueProc&&... proc)
{
return query_multi_with_params<std::tuple<>, ValueProc...>(query_text, strlen(query_text), std::make_tuple(), std::forward<ValueProc>(proc)...);
}
template<typename... ValueProc>
base_database& query_multi(const std::string& query_text, ValueProc&&... proc)
{
return query_multi_with_params<std::tuple<>, ValueProc...>(query_text.data(), query_text.size(), std::make_tuple(), std::forward<ValueProc>(proc)...);
}
template<typename Params, typename Values>
bool query_first(const char* query_text, size_t text_length, const Params& params, Values&& values)
{
first_record fetcher;
query_explicit(query_text, text_length, params, std::forward<Values>(values), std::ref(fetcher));
return fetcher;
}
template<typename Params, typename Values>
bool query_first(const char* query_text, const Params& params, Values&& values)
{
first_record fetcher;
query_explicit(query_text, strlen(query_text), params, std::forward<Values>(values), std::ref(fetcher));
return fetcher;
}
template<typename Params, typename Values>
bool query_first(const std::string& query_text, const Params& params, Values&& values)
{
first_record fetcher;
return query_explicit(query_text, params, values, std::ref(fetcher));
return fetcher;
}
template<typename Values>
bool query_first(const char* query_text, size_t text_length, Values&& values)
{
first_record fetcher;
return query_explicit(query_text, text_length, std::make_tuple(), std::forward<Values>(values), std::ref(fetcher));
return fetcher;
}
template<typename Values>
bool query_first(const char* query_text, Values&& values)
{
first_record fetcher;
query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward<Values>(values), std::ref(fetcher));
return fetcher;
}
template<typename Values>
bool query_first(const std::string& query_text, Values&& values)
{
first_record fetcher;
return query_explicit(query_text, std::make_tuple(), std::forward<Values>(values), std::ref(fetcher));
return fetcher;
}
template<typename... Values>
bool query_first_direct(const char* query_text, size_t text_length, Values&... values)
{
return query_first(query_text, text_length, std::tie(values...));
}
template<typename... Values>
bool query_first_direct(const char* query_text, Values&... values)
{
return query_first(query_text, std::tie(values...));
}
template<typename... Values>
bool query_first_direct(const std::string& query_text, Values&... values)
{
return query_first(query_text, std::tie(values...));
}
protected:
struct nothing
{
template<typename... Values> bool operator()(Values&&...) const { return true; }
};
struct first_record
{
first_record() : _found(false) { }
template<typename... Values> bool operator()(Values&&...) { _found = true; return false; }
operator bool() const { return _found; }
private:
bool _found;
};
};
class blobbuf : public std::streambuf
{
public:
blobbuf() = default;
blobbuf(const blobbuf&) = default;
blobbuf& operator=(const blobbuf&) = default;
virtual ~blobbuf()
{
overflow();
}
void swap(blobbuf& other)
{
std::swap(m_buf, other.m_buf);
std::swap(m_size, other.m_size);
std::swap(m_pos, other.m_pos);
std::streambuf::swap(other);
}
protected:
virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir,
std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override
{
if (which&std::ios_base::in)
{
pos_type pos = 0;
pos = seekoff(m_pos, off, dir);
return seekpos(pos, which);
}
return std::streambuf::seekoff(off, dir, which);
}
virtual pos_type seekpos(pos_type pos,
std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override
{
if (pos >= m_size)
return pos_type(off_type(-1));
if (which&std::ios_base::out)
{
if (pos < m_pos || pos >= m_pos + off_type(egptr() - pbase()))
{
overflow();
m_pos = pos;
setp(m_buf.data(), m_buf.data() + m_buf.size());
}
else
{
pbump(off_type(pos - pabs()));
}
}
else if (which&std::ios_base::in)
{
if (pos < m_pos || pos >= m_pos + off_type(epptr() - eback()))
{
m_pos = pos;
setg(m_buf.data(), m_buf.data(), m_buf.data());
}
else
{
gbump(off_type(pos - gabs()));
}
}
return pos;
}
virtual std::streamsize showmanyc() override
{
return m_size - pabs();
}
virtual int_type underflow() override
{
if (pptr() > pbase())
overflow();
off_type count = egptr() - eback();
pos_type next_pos = 0;
if (count == 0 && eback() == m_buf.data())
{
setg(m_buf.data(), m_buf.data(), m_buf.data() + m_buf.size());
count = m_buf.size();
}
else
{
next_pos = m_pos + pos_type(count);
}
if (next_pos >= m_size)
return traits_type::eof();
count = std::min(count, m_size - next_pos);
m_pos = next_pos;
if (read_blob(m_buf.data(), count, m_pos))
{
setg(eback(), eback(), eback() + count);
return traits_type::to_int_type(*gptr());
}
else
{
return traits_type::eof();
}
}
virtual int_type overflow(int_type ch = traits_type::eof()) override
{
if (pptr() != pbase())
{
size_t count = pptr() - pbase();
write_blob(pbase(), count);
//auto intersection = interval_intersection(m_pos, egptr() - eback(), m_pos, epptr() - pbase());
//if (intersection.first != intersection.second)
//{
// commit(intersection.first, intersection.second);
//}
m_pos += count;
setp(pbase(), epptr());
}
if (!traits_type::eq_int_type(ch, traits_type::eof()))
{
char_type c = traits_type::to_char_type(ch);
if (m_pos >= m_size)
return traits_type::eof();
write_blob(&c, 1);
//auto intersection = interval_intersection(m_pos, egptr() - eback(), m_pos, 1);
//if (intersection.first != intersection.second)
//{
// eback()[intersection.first - m_pos] = c;
//}
m_pos += 1;
}
return ch;
}
virtual int_type pbackfail(int_type c = traits_type::eof()) override
{
if (gptr() == 0
|| gptr() <= eback()
|| (!traits_type::eq_int_type(traits_type::eof(), c)
&& !traits_type::eq(traits_type::to_char_type(c), gptr()[-1])))
{
return (traits_type::eof()); // can't put back, fail
}
else
{ // back up one position and store put-back character
gbump(-1);
if (!traits_type::eq_int_type(traits_type::eof(), c))
*gptr() = traits_type::to_char_type(c);
return (traits_type::not_eof(c));
}
}
private:
off_type seekoff(off_type position, off_type off, std::ios_base::seekdir dir)
{
off_type result = 0;
switch (dir)
{
case std::ios_base::beg:
result = off;
break;
case std::ios_base::cur:
result = position + off;
break;
case std::ios_base::end:
result = m_size - off;
}
if (result > m_size)
result = m_size;
return result;
}
pos_type gabs() const // absolute offset of input pointer in blob field
{
return m_pos + off_type(gptr() - eback());
}
pos_type pabs() const // absolute offset of output pointer in blob field
{
return m_pos + off_type(pptr() - pbase());
}
protected:
std::vector<char> m_buf;
pos_type m_size;
pos_type m_pos; //position in the input sequence
virtual bool read_blob(char* buffer, off_type& count, pos_type position) = 0;
virtual void write_blob(const char* buffer, size_t count) = 0;
void init_buffer(std::ios_base::openmode mode)
{
size_t bufsize;
if (m_size > 0)
bufsize = std::min<size_t>(blob_buffer_size, m_size);
else
bufsize = blob_buffer_size;
if (mode&std::ios_base::in)
{
m_buf.resize(bufsize);
m_pos = 0;
setg(m_buf.data(), m_buf.data(), m_buf.data());
}
else if (mode&std::ios_base::out)
{
m_buf.resize(bufsize);
m_pos = 0;
setp(m_buf.data(), m_buf.data() + bufsize);
}
}
};
typedef std::function<void(std::ostream&)> blob_writer;
template<typename Database>
struct transaction
{
transaction(Database& db) : m_db(db), m_commited(true)
{
begin();
}
~transaction()
{
rollback();
}
void begin()
{
if(m_commited)
{
m_db.begin_transaction();
m_commited=false;
}
}
void rollback()
{
if(!m_commited)
{
m_db.rollback();
m_commited=true;
}
}
void commit()
{
if(!m_commited)
{
m_db.commit();
m_commited=true;
}
}
private:
bool m_commited;
Database& m_db;
};
template<typename Command, typename Params, typename... Others>
inline void execute(Command& command, uint64_t* affected, const Params& params)
{
command.reset();
command.execute(params);
if(affected) *affected+=command.affetced_rows();
}
template<typename Command, typename Params, typename... Others>
inline void execute(Command& command, uint64_t* affected, const Params& params, const Others&... others)
{
execute(command, affected, params);
execute(command, affected, others...);
}
}
#endif //_QTL_COMMON_H_