* refactored file structuremaster
@@ -0,0 +1,20 @@ | |||
#pragma once | |||
#include <mariadb/column.h> | |||
#include <mariadb/connection.h> | |||
#include <mariadb/database.h> | |||
#include <mariadb/enums.h> | |||
#include <mariadb/exception.h> | |||
#include <mariadb/field.h> | |||
#include <mariadb/result.h> | |||
#include <mariadb/row.h> | |||
#include <mariadb/statement.h> | |||
#include <mariadb/transaction.h> | |||
#include <mariadb/inline/connection.inl> | |||
#include <mariadb/inline/database.inl> | |||
#include <mariadb/inline/field.inl> | |||
#include <mariadb/inline/result.inl> | |||
#include <mariadb/inline/row.inl> | |||
#include <mariadb/inline/statement.inl> | |||
#include <mariadb/inline/transaction.inl> |
@@ -0,0 +1,41 @@ | |||
#pragma once | |||
#include <string> | |||
#include <vector> | |||
#include <mariadb/config.h> | |||
#include <mariadb/enums.h> | |||
#include <mariadb/forward/column.h> | |||
namespace mariadb | |||
{ | |||
struct column | |||
{ | |||
std::string name; | |||
std::string original_name; | |||
std::string table; | |||
std::string original_table; | |||
std::string database; | |||
unsigned long length; | |||
unsigned long max_length; | |||
column_flags flags; | |||
unsigned int decimals; | |||
unsigned int charset_number; | |||
column_type type; | |||
inline column(MYSQL_FIELD& f) | |||
: name (f.name, f.name_length) | |||
, original_name (f.org_name, f.org_name_length) | |||
, table (f.table, f.table_length) | |||
, original_table(f.org_table, f.org_table_length) | |||
, database (f.db, f.db_length) | |||
, length (f.length) | |||
, max_length (f.max_length) | |||
, flags (f.flags) | |||
, decimals (f.decimals) | |||
, charset_number(f.charsetnr) | |||
, type (static_cast<column_type>(f.type)) | |||
{ } | |||
}; | |||
} |
@@ -0,0 +1,7 @@ | |||
#pragma once | |||
#ifndef MARIADB_MOCK | |||
#include <mariadb/mysql.h> | |||
#include <mariadb/errmsg.h> | |||
#include <mariadb/mysqld_error.h> | |||
#endif |
@@ -0,0 +1,48 @@ | |||
#pragma once | |||
#include <memory> | |||
#include <mariadb/config.h> | |||
#include <mariadb/impl/mariadb_handle.h> | |||
#include <mariadb/forward/connection.h> | |||
#include <mariadb/forward/result.h> | |||
#include <mariadb/forward/statement.h> | |||
namespace mariadb | |||
{ | |||
struct connection | |||
: public __impl::mariadb_handle<MYSQL*> | |||
{ | |||
private: | |||
std::unique_ptr<result> _result; | |||
template<class T> | |||
typename T::result_type* execute_internal(const std::string& cmd); | |||
public: | |||
inline void execute (const std::string& cmd); | |||
inline unsigned long long execute_id (const std::string& cmd); | |||
inline unsigned long long execute_rows (const std::string& cmd); | |||
inline result_stored* execute_stored (const std::string& cmd); | |||
inline result_used* execute_used (const std::string& cmd); | |||
inline void execute (const statement& s); | |||
inline unsigned long long execute_id (const statement& s); | |||
inline unsigned long long execute_rows (const statement& s); | |||
inline result_stored* execute_stored (const statement& s); | |||
inline result_used* execute_used (const statement& s); | |||
inline result* result () const; | |||
inline uint fieldcount () const; | |||
inline std::string escape (const std::string& value) const; | |||
inline void close (); | |||
inline connection& operator =(connection&& other); | |||
inline connection(); | |||
inline connection(MYSQL* h); | |||
inline connection(connection&& other); | |||
inline ~connection(); | |||
}; | |||
} |
@@ -0,0 +1,23 @@ | |||
#pragma once | |||
#include <string> | |||
#include <mariadb/config.h> | |||
#include <mariadb/enums.h> | |||
#include <mariadb/forward/connection.h> | |||
namespace mariadb | |||
{ | |||
struct database | |||
{ | |||
static inline connection connect (const std::string& host, | |||
const uint& port, | |||
const std::string& user, | |||
const std::string& password, | |||
const std::string& database, | |||
const client_flags& flags); | |||
static inline error_code error_code(MYSQL* handle); | |||
static inline std::string error_msg (MYSQL* handle); | |||
}; | |||
} |
@@ -0,0 +1,26 @@ | |||
#pragma once | |||
#include <mariadb/config.h> | |||
#include <mariadb/enums.h> | |||
#include <cpputils/misc/exception.h> | |||
namespace mariadb | |||
{ | |||
struct exception : public utl::exception | |||
{ | |||
protected: | |||
void print_message(std::ostream& os) const override; | |||
public: | |||
error_code error; | |||
std::string query; | |||
inline exception(const std::string& msg, error_code err, const std::string& q = std::string()) | |||
: utl::exception(msg) | |||
, error (err) | |||
, query (q) | |||
{ } | |||
}; | |||
} |
@@ -0,0 +1,34 @@ | |||
#pragma once | |||
#include <mariadb/config.h> | |||
#include <mariadb/forward/column.h> | |||
#include <mariadb/forward/field.h> | |||
#include <mariadb/forward/row.h> | |||
namespace mariadb | |||
{ | |||
struct field | |||
{ | |||
private: | |||
const row& _row; | |||
const size_t _index; | |||
const char* _data; | |||
size_t _size; | |||
public: | |||
inline size_t index () const; | |||
inline const column& column () const; | |||
inline bool is_null () const; | |||
inline bool is_empty() const; | |||
inline const char* data () const; | |||
inline size_t size () const; | |||
inline operator bool () const; | |||
template <class T> | |||
inline T get() const; | |||
inline field(const row& r, size_t i, const char* d, size_t s); | |||
}; | |||
} |
@@ -0,0 +1,12 @@ | |||
#pragma once | |||
#include <mariadb/config.h> | |||
namespace mariadb | |||
{ | |||
struct column; | |||
using column_vector = std::vector<column>; | |||
} |
@@ -0,0 +1,10 @@ | |||
#pragma once | |||
#include <mariadb/config.h> | |||
namespace mariadb | |||
{ | |||
struct connection; | |||
} |
@@ -0,0 +1,10 @@ | |||
#pragma once | |||
#include <mariadb/config.h> | |||
namespace mariadb | |||
{ | |||
struct database; | |||
} |
@@ -0,0 +1,10 @@ | |||
#pragma once | |||
#include <mariadb/config.h> | |||
namespace mariadb | |||
{ | |||
struct field; | |||
} |
@@ -0,0 +1,14 @@ | |||
#pragma once | |||
#include <mariadb/config.h> | |||
namespace mariadb | |||
{ | |||
struct result; | |||
struct result_used; | |||
struct result_stored; | |||
} |
@@ -0,0 +1,10 @@ | |||
#pragma once | |||
#include <mariadb/config.h> | |||
namespace mariadb | |||
{ | |||
struct row; | |||
} |
@@ -0,0 +1,10 @@ | |||
#pragma once | |||
#include <mariadb/config.h> | |||
namespace mariadb | |||
{ | |||
struct statement; | |||
} |
@@ -0,0 +1,10 @@ | |||
#pragma once | |||
#include <mariadb/config.h> | |||
namespace mariadb | |||
{ | |||
struct transaction; | |||
} |
@@ -0,0 +1,38 @@ | |||
#pragma once | |||
#include <mariadb/config.h> | |||
namespace mariadb { | |||
namespace __impl | |||
{ | |||
template<class T> | |||
struct mariadb_handle | |||
{ | |||
private: | |||
T _handle; | |||
protected: | |||
inline void handle(T h) | |||
{ _handle = h; } | |||
public: | |||
inline operator T() const | |||
{ return _handle; } | |||
inline const T& handle() const | |||
{ return _handle; } | |||
mariadb_handle(T h) : | |||
_handle(h) | |||
{ }; | |||
mariadb_handle(mariadb_handle&& other) : | |||
_handle(other._handle) | |||
{ other._handle = nullptr; } | |||
private: | |||
mariadb_handle(const mariadb_handle&) = delete; | |||
}; | |||
} } |
@@ -0,0 +1,152 @@ | |||
#pragma once | |||
#include <mariadb/result.h> | |||
#include <mariadb/connection.h> | |||
#include <mariadb/inline/result.inl> | |||
#include <mariadb/inline/database.inl> | |||
#include <mariadb/inline/statement.inl> | |||
namespace mariadb | |||
{ | |||
/* op_store_result ***************************************************************************/ | |||
struct op_store_result | |||
{ | |||
using result_type = result_stored; | |||
inline MYSQL_RES* operator()(MYSQL* handle) const | |||
{ return mysql_store_result(handle); } | |||
}; | |||
/* op_use_result *****************************************************************************/ | |||
struct op_use_result | |||
{ | |||
using result_type = result_used; | |||
inline MYSQL_RES* operator()(MYSQL* handle) const | |||
{ return mysql_use_result(handle); } | |||
}; | |||
/* connection ********************************************************************************/ | |||
template<class T> | |||
typename T::result_type* connection::execute_internal(const std::string& cmd) | |||
{ | |||
#ifdef MARIADB_DEBUG | |||
log_global_message(debug) << "execute mariadb query: " << std::endl << cmd; | |||
#endif | |||
if (!handle()) | |||
throw exception("invalid handle", error_code::Unknown, cmd); | |||
using result_type = typename T::result_type; | |||
_result.reset(); | |||
if (mysql_real_query(*this, cmd.data(), cmd.size()) != 0) | |||
throw exception(database::error_msg(*this), database::error_code(*this), cmd); | |||
auto ret = T()(*this); | |||
if (!ret) | |||
{ | |||
if (mysql_field_count(*this) > 0) | |||
throw exception(database::error_msg(*this), database::error_code(*this), cmd); | |||
return nullptr; | |||
} | |||
_result.reset(new result_type(ret)); | |||
return static_cast<result_type*>(_result.get()); | |||
} | |||
inline void connection::execute(const std::string& cmd) | |||
{ execute_internal<op_store_result>(cmd); } | |||
inline unsigned long long connection::execute_id(const std::string& cmd) | |||
{ | |||
execute_internal<op_store_result>(cmd); | |||
auto id = mysql_insert_id(*this); | |||
if (id == static_cast<unsigned long long>(-1)) | |||
throw exception(database::error_msg(*this), database::error_code(*this), cmd); | |||
return id; | |||
} | |||
inline unsigned long long connection::execute_rows(const std::string& cmd) | |||
{ | |||
execute_internal<op_store_result>(cmd); | |||
auto rows = mysql_affected_rows(*this); | |||
if (rows == static_cast<unsigned long long>(-1)) | |||
throw exception(database::error_msg(*this), database::error_code(*this), cmd); | |||
return rows; | |||
} | |||
inline result_stored* connection::execute_stored(const std::string& cmd) | |||
{ return execute_internal<op_store_result>(cmd); } | |||
inline result_used* connection::execute_used(const std::string& cmd) | |||
{ return execute_internal<op_use_result>(cmd); } | |||
inline void connection::execute(const statement& s) | |||
{ return execute(s.query(*this)); } | |||
inline unsigned long long connection::execute_id(const statement& s) | |||
{ return execute_id(s.query(*this)); } | |||
inline unsigned long long connection::execute_rows(const statement& s) | |||
{ return execute_rows(s.query(*this)); } | |||
inline result_stored* connection::execute_stored(const statement& s) | |||
{ return execute_stored(s.query(*this)); } | |||
inline result_used* connection::execute_used(const statement& s) | |||
{ return execute_used(s.query(*this)); } | |||
inline result* connection::result() const | |||
{ return _result.get(); } | |||
inline uint connection::fieldcount() const | |||
{ return mysql_field_count(handle()); } | |||
inline std::string connection::escape(const std::string& value) const | |||
{ | |||
if (handle()) | |||
{ | |||
std::string ret; | |||
ret.resize(2 * value.size() + 1); | |||
auto len = mysql_real_escape_string(handle(), const_cast<char*>(ret.data()), value.c_str(), value.size()); | |||
ret.resize(len); | |||
return ret; | |||
} | |||
return value; | |||
} | |||
inline void connection::close() | |||
{ | |||
_result.reset(); | |||
auto h = handle(); | |||
handle(nullptr); | |||
if (h) | |||
mysql_close(h); | |||
} | |||
inline connection& connection::operator =(connection&& other) | |||
{ | |||
close(); | |||
handle(other.handle()); | |||
other.handle(nullptr); | |||
return *this; | |||
} | |||
inline connection::connection() | |||
: connection(nullptr) | |||
{ } | |||
inline connection::connection(MYSQL* h) | |||
: mariadb_handle(h) | |||
{ } | |||
inline connection::connection(connection&& other) | |||
: mariadb_handle(std::move(other)) | |||
, _result (std::move(other)._result) | |||
{ } | |||
inline connection::~connection() | |||
{ close(); } | |||
} |
@@ -0,0 +1,48 @@ | |||
#pragma once | |||
#include <mariadb/database.h> | |||
namespace mariadb | |||
{ | |||
/* database ***********************************************************************************/ | |||
inline connection database::connect( | |||
const std::string& host, | |||
const uint& port, | |||
const std::string& user, | |||
const std::string& password, | |||
const std::string& database, | |||
const client_flags& flags) | |||
{ | |||
auto handle = mysql_init(nullptr); | |||
if (!handle) | |||
throw exception("unable to initialize connection handle", error_code::Unknown); | |||
if (!mysql_real_connect( | |||
handle, | |||
host.c_str(), | |||
user.c_str(), | |||
password.c_str(), | |||
database.empty() ? static_cast<const char*>(nullptr) : database.c_str(), | |||
port, | |||
nullptr, | |||
flags.value)) | |||
throw exception(database::error_msg(handle), database::error_code(handle)); | |||
return connection(handle); | |||
} | |||
inline error_code database::error_code(MYSQL* handle) | |||
{ | |||
auto ret = mysql_errno(handle); | |||
return static_cast<enum error_code>(ret); | |||
} | |||
inline std::string database::error_msg(MYSQL* handle) | |||
{ | |||
auto ret = mysql_error(handle); | |||
return (ret ? std::string(ret) : std::string()); | |||
} | |||
} |
@@ -0,0 +1,81 @@ | |||
#pragma once | |||
#include <mariadb/row.h> | |||
#include <mariadb/field.h> | |||
#include <cpputils/misc/enum.h> | |||
#include <cpputils/misc/string.h> | |||
namespace mariadb | |||
{ | |||
/* op_field_converter ************************************************************************/ | |||
template<class T, class Enable = void> | |||
struct op_field_converter; | |||
template<typename T> | |||
struct op_field_converter<T, void> | |||
{ | |||
inline T operator()(const char* c, size_t s) const | |||
{ | |||
T tmp; | |||
std::string data(c, s); | |||
if (!utl::try_from_string(data, tmp)) | |||
throw exception(std::string("unable to convert field data (data=") + data + ")", error_code::UnknownError); | |||
return tmp; | |||
} | |||
}; | |||
template<> | |||
struct op_field_converter<const char*, void> | |||
{ | |||
inline const char* operator()(const char* c, size_t s) const | |||
{ return c; } | |||
}; | |||
template<> | |||
struct op_field_converter<std::string, void> | |||
{ | |||
inline std::string operator()(const char* c, size_t s) const | |||
{ return std::string(c, s); } | |||
}; | |||
/* field *************************************************************************************/ | |||
inline size_t field::index() const | |||
{ return _index; } | |||
inline const column& field::column() const | |||
{ return _row.columns().at(_index); } | |||
inline bool field::is_null() const | |||
{ return (_data == nullptr); } | |||
inline bool field::is_empty() const | |||
{ return (_size == 0); } | |||
inline const char* field::data() const | |||
{ return _data; } | |||
inline size_t field::size() const | |||
{ return _size; } | |||
template <class T> | |||
inline T field::get() const | |||
{ | |||
if (is_null()) | |||
throw exception("field is null", error_code::UnknownError); | |||
return op_field_converter<T>()(_data, _size); | |||
} | |||
inline field::operator bool() const | |||
{ return !is_null() && !is_empty(); } | |||
inline field::field(const row& r, size_t i, const char* d, size_t s) | |||
: _row (r) | |||
, _index(i) | |||
, _data (d) | |||
, _size (s) | |||
{ } | |||
} |
@@ -0,0 +1,71 @@ | |||
#pragma once | |||
#include <mariadb/result.h> | |||
namespace mariadb | |||
{ | |||
/* result ************************************************************************************/ | |||
inline void result::rowindex(unsigned long long value) | |||
{ _rowindex = value; } | |||
inline unsigned int result::columncount() const | |||
{ return mysql_num_fields(*this); } | |||
inline const column_vector& result::columns() const | |||
{ | |||
if (_columns.empty()) | |||
update_columns(); | |||
return _columns; | |||
} | |||
inline row* result::current() const | |||
{ return _row.get(); } | |||
inline unsigned long long result::rowindex() const | |||
{ return _rowindex; } | |||
inline void result::free() | |||
{ | |||
auto h = handle(); | |||
handle(nullptr); | |||
mysql_free_result(h); | |||
} | |||
inline result::result(MYSQL_RES* h) | |||
: mariadb_handle(h) | |||
, _rowindex (static_cast<unsigned long long>(-1)) | |||
{ } | |||
/* result_stored ******************************************************************************/ | |||
inline MYSQL_ROW_OFFSET result_stored::rowoffset() const | |||
{ return mysql_row_tell(*this); } | |||
inline void result_stored::rowoffset(MYSQL_ROW_OFFSET offset) | |||
{ mysql_row_seek(*this, offset); } | |||
inline void result_stored::rowindex(unsigned long long index) | |||
{ | |||
result::rowindex(index); | |||
mysql_data_seek(*this, result::rowindex()); | |||
} | |||
inline unsigned long long result_stored::rowindex() const | |||
{ return result::rowindex(); } | |||
inline unsigned long long result_stored::rowcount() const | |||
{ return mysql_num_rows(*this); } | |||
inline result_stored::result_stored(MYSQL_RES* h) | |||
: result(h) | |||
{ } | |||
/* result_used *******************************************************************************/ | |||
inline result_used::result_used(MYSQL_RES* h) | |||
: result(h) | |||
{ } | |||
} |
@@ -0,0 +1,234 @@ | |||
#pragma once | |||
#include <mariadb/row.h> | |||
#include <mariadb/field.h> | |||
#include <mariadb/result.h> | |||
namespace mariadb | |||
{ | |||
/* row::iterator_tpl *************************************************************************/ | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::compare_result | |||
row::iterator_tpl<T>::compare(const this_type& other) const | |||
{ | |||
if (_owner != other._owner) | |||
return compare_result::mismatch; | |||
else if (_index < other._index) | |||
return compare_result::lower; | |||
else if (_index > other._index) | |||
return compare_result::greater; | |||
else | |||
return compare_result::equals; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::reference | |||
row::iterator_tpl<T>::field() const | |||
{ | |||
if (!_cache) | |||
_cache.reset(new value_type(_owner->at(_index))); | |||
return *_cache; | |||
} | |||
template<typename T> | |||
inline void row::iterator_tpl<T>::assign(const this_type& other) | |||
{ | |||
_owner = other._owner; | |||
_index = other._index; | |||
_direction = other._direction; | |||
_cache.reset(); | |||
} | |||
template<typename T> | |||
inline void row::iterator_tpl<T>::next(difference_type i) | |||
{ | |||
_cache.reset(); | |||
_index = _index + _direction * i; | |||
} | |||
template<typename T> | |||
inline void row::iterator_tpl<T>::prev(difference_type i) | |||
{ | |||
_cache.reset(); | |||
_index = _index - _direction * i; | |||
} | |||
template<typename T> | |||
inline bool row::iterator_tpl<T>::operator==(const this_type& other) const | |||
{ return compare(other) == compare_result::equals; } | |||
template<typename T> | |||
inline bool row::iterator_tpl<T>::operator!=(const this_type& other) const | |||
{ return compare(other) != compare_result::equals; } | |||
template<typename T> | |||
inline bool row::iterator_tpl<T>::operator<(const this_type& other) const | |||
{ return compare(other) == compare_result::less; } | |||
template<typename T> | |||
inline bool row::iterator_tpl<T>::operator<=(const this_type& other) const | |||
{ | |||
auto c = compare(other); | |||
return (c == compare_result::less || c == compare_result::equals); | |||
} | |||
template<typename T> | |||
inline bool row::iterator_tpl<T>::operator>(const this_type& other) const | |||
{ return compare(other) == compare_result::greater; } | |||
template<typename T> | |||
inline bool row::iterator_tpl<T>::operator>=(const this_type& other) const | |||
{ | |||
auto c = compare(other); | |||
return (c == compare_result::greater || c == compare_result::equals); | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::reference | |||
row::iterator_tpl<T>::operator*() const | |||
{ return field(); } | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::pointer | |||
row::iterator_tpl<T>::operator->() const | |||
{ return &field(); } | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type& | |||
row::iterator_tpl<T>::operator++() | |||
{ | |||
next(); | |||
return *this; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type& | |||
row::iterator_tpl<T>::operator--() | |||
{ | |||
prev(); | |||
return *this; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type | |||
row::iterator_tpl<T>::operator++(int) | |||
{ | |||
auto tmp(*this); | |||
next(); | |||
return tmp; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type | |||
row::iterator_tpl<T>::operator--(int) | |||
{ | |||
auto tmp(*this); | |||
prev(); | |||
return tmp; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type& | |||
row::iterator_tpl<T>::operator+=(difference_type diff) | |||
{ | |||
next(diff); | |||
return *this; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type& | |||
row::iterator_tpl<T>::operator-=(difference_type diff) | |||
{ | |||
prev(diff); | |||
return *this; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type | |||
row::iterator_tpl<T>::operator+(difference_type diff) const | |||
{ | |||
auto tmp(*this); | |||
tmp += diff; | |||
return tmp; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type | |||
row::iterator_tpl<T>::operator-(difference_type diff) const | |||
{ | |||
auto tmp(*this); | |||
tmp -= diff; | |||
return tmp; | |||
} | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::difference_type | |||
row::iterator_tpl<T>::operator-(const this_type& other) const | |||
{ return (_index - other._index) * _direction; } | |||
template<typename T> | |||
inline typename row::iterator_tpl<T>::this_type | |||
row::iterator_tpl<T>::operator[] (difference_type diff) | |||
{ | |||
auto tmp(*this); | |||
tmp += diff; | |||
return tmp; | |||
} | |||
template<typename T> | |||
inline row::iterator_tpl<T>::iterator_tpl(const row& p_row, ssize_t index, ssize_t direction) | |||
: _owner (&p_row) | |||
, _index (index) | |||
, _direction(direction) | |||
{ } | |||
template<typename T> | |||
inline row::iterator_tpl<T>::iterator_tpl(const this_type& other) | |||
{ assign(other); } | |||
/* row ***************************************************************************************/ | |||
inline const column_vector& row::columns() const | |||
{ return _result.columns(); } | |||
inline unsigned int row::size() const | |||
{ return _result.columncount(); } | |||
inline row::iterator_type row::begin() const | |||
{ return iterator_type(*this, 0, 1); } | |||
inline row::iterator_type row::end() const | |||
{ return iterator_type(*this, size(), 1); } | |||
inline row::const_iterator_type row::cbegin() const | |||
{ return const_iterator_type(*this, 0, 1); } | |||
inline row::const_iterator_type row::cend() const | |||
{ return const_iterator_type(*this, size(), 1); } | |||
inline row::iterator_type row::rbegin() const | |||
{ return iterator_type(*this, size()-1, -1); } | |||
inline row::iterator_type row::rend() const | |||
{ return iterator_type(*this, -1, -1); } | |||
inline row::const_iterator_type row::crbegin() const | |||
{ return const_iterator_type(*this, size()-1, -1); } | |||
inline row::const_iterator_type row::crend() const | |||
{ return const_iterator_type(*this, -1, -1); } | |||
inline field row::operator[](size_t i) const | |||
{ return at(i); } | |||
inline field row::operator[](const std::string& name) const | |||
{ return at(name); } | |||
inline row::row(const result& p_result, MYSQL_ROW p_row) | |||
: mariadb_handle(p_row) | |||
, _result (p_result) | |||
, _lengths (nullptr) | |||
{ } | |||
} |
@@ -0,0 +1,89 @@ | |||
#pragma once | |||
#include <mariadb/statement.h> | |||
#include <cpputils/misc/enum.h> | |||
#include <cpputils/misc/string.h> | |||
namespace mariadb | |||
{ | |||
/* statement *********************************************************************************/ | |||
inline void statement::assign(const std::string& query) | |||
{ | |||
_changed = true; | |||
parse(query); | |||
} | |||
inline const std::string& statement::query(const connection& con) const | |||
{ | |||
if (_changed || &con != _connection) | |||
build(con); | |||
return _query; | |||
} | |||
inline size_t statement::find(const std::string& param) | |||
{ | |||
for (size_t i = 0; i < _parameters.size(); ++i) | |||
{ | |||
if (_parameters.at(i).first == param) | |||
return i; | |||
} | |||
return npos; | |||
} | |||
inline void statement::set_null(const std::string& param) | |||
{ | |||
auto i = find(param); | |||
if (i == npos) | |||
throw exception(std::string("unknown parameter name in query: ") + param, error_code::Unknown); | |||
set_null(i); | |||
} | |||
inline void statement::set_null(size_t index) | |||
{ | |||
if (index >= _parameters.size()) | |||
throw exception(std::string("unknown parameter index in query: ") + std::to_string(index), error_code::Unknown); | |||
auto& param = _parameters.at(index).second; | |||
param.has_value = false; | |||
_changed = true; | |||
} | |||
inline void statement::clear() | |||
{ | |||
for (auto& param : _parameters) | |||
param.second.has_value = false; | |||
} | |||
template<class T> | |||
inline void statement::set(const std::string& param, const T& value) | |||
{ | |||
auto i = find(param); | |||
if (i == npos) | |||
throw exception(std::string("unknown parameter name in query: ") + param, error_code::Unknown); | |||
set<T>(i, value); | |||
} | |||
template<class T> | |||
inline void statement::set(size_t index, const T& value) | |||
{ | |||
if (index >= _parameters.size()) | |||
throw exception(std::string("unknown parameter index in query: ") + std::to_string(index), error_code::Unknown); | |||
auto& param = _parameters.at(index).second; | |||
param.has_value = true; | |||
param.value = utl::to_string(value); | |||
_changed = true; | |||
} | |||
inline statement::statement() | |||
: _changed (true) | |||
, _connection (nullptr) | |||
{ } | |||
inline statement::statement(const std::string& query) | |||
: _changed (true) | |||
, _connection (nullptr) | |||
{ parse(query); } | |||
} |
@@ -0,0 +1,46 @@ | |||
#pragma once | |||
#include <mariadb/transaction.h> | |||
namespace mariadb | |||
{ | |||
/* transaction *******************************************************************************/ | |||
inline void transaction::begin() | |||
{ | |||
static const statement sCommit("START TRANSACTION"); | |||
_connection.execute_rows(sCommit); | |||
} | |||
inline void transaction::commit() | |||
{ | |||
static const statement sCommit("COMMIT"); | |||
if (_closed) | |||
throw exception("transaction is already closed", error_code::Unknown); | |||
_connection.execute_rows(sCommit); | |||
_closed = true; | |||
} | |||
inline void transaction::rollback() | |||
{ | |||
static const statement sRollback("ROLLBACK"); | |||
if (_closed) | |||
throw exception("transaction is already closed", error_code::Unknown); | |||
_connection.execute_rows(sRollback); | |||
_closed = true; | |||
} | |||
inline transaction::transaction(connection& connection) : | |||
_connection (connection), | |||
_closed (false) | |||
{ begin(); } | |||
inline transaction::~transaction() | |||
{ | |||
if (!_closed) | |||
rollback(); | |||
} | |||
} |
@@ -0,0 +1,56 @@ | |||
#pragma once | |||
#include <memory> | |||
#include <mariadb/config.h> | |||
#include <mariadb/impl/mariadb_handle.h> | |||
#include <mariadb/forward/column.h> | |||
#include <mariadb/forward/row.h> | |||
namespace mariadb | |||
{ | |||
struct result : | |||
public __impl::mariadb_handle<MYSQL_RES*> | |||
{ | |||
private: | |||
std::unique_ptr<row> _row; | |||
mutable column_vector _columns; | |||
unsigned long long _rowindex; | |||
void update_columns() const; | |||
protected: | |||
inline void rowindex(unsigned long long value); | |||
public: | |||
inline unsigned int columncount () const; | |||
inline const column_vector& columns () const; | |||
row* next (); | |||
inline row* current () const; | |||
inline unsigned long long rowindex () const; | |||
inline void free (); | |||
inline result(MYSQL_RES* h); | |||
virtual ~result(); | |||
}; | |||
struct result_stored | |||
: public result | |||
{ | |||
inline MYSQL_ROW_OFFSET rowoffset () const; | |||
inline void rowoffset (MYSQL_ROW_OFFSET offset); | |||
inline void rowindex (unsigned long long index); | |||
inline unsigned long long rowindex () const; | |||
inline unsigned long long rowcount () const; | |||
inline result_stored(MYSQL_RES* h); | |||
}; | |||
struct result_used | |||
: public result | |||
{ | |||
inline result_used(MYSQL_RES* h); | |||
virtual ~result_used() override; | |||
}; | |||
} |
@@ -0,0 +1,108 @@ | |||
#pragma once | |||
#include <string> | |||
#include <limits> | |||
#include <memory> | |||
#include <mariadb/config.h> | |||
#include <mariadb/impl/mariadb_handle.h> | |||
#include <mariadb/forward/column.h> | |||
#include <mariadb/forward/field.h> | |||
#include <mariadb/forward/result.h> | |||
#include <mariadb/forward/row.h> | |||
namespace mariadb | |||
{ | |||
struct row | |||
: public __impl::mariadb_handle<MYSQL_ROW> | |||
{ | |||
private: | |||
template<typename T> | |||
struct iterator_tpl | |||
{ | |||
public: | |||
using this_type = iterator_tpl<T>; | |||
using iterator_category = std::random_access_iterator_tag; | |||
using value_type = T; | |||
using difference_type = ssize_t; | |||
using pointer = T*; | |||
using reference = T&; | |||
private: | |||
enum class compare_result : int | |||
{ | |||
lower = -1, | |||
equals = 0, | |||
greater = 1, | |||
mismatch = 2 | |||
}; | |||
using value_ptru_type = std::unique_ptr<value_type>; | |||
private: | |||
const row* _owner; | |||
ssize_t _index; | |||
ssize_t _direction; | |||
mutable value_ptru_type _cache; | |||
inline compare_result compare (const this_type& other) const; | |||
inline reference field () const; | |||
inline void assign (const this_type& other); | |||
inline void next (difference_type i = 1); | |||
inline void prev (difference_type i = 1); | |||
public: | |||
inline bool operator == (const this_type& other) const; | |||
inline bool operator != (const this_type& other) const; | |||
inline bool operator < (const this_type& other) const; | |||
inline bool operator <= (const this_type& other) const; | |||
inline bool operator > (const this_type& other) const; | |||
inline bool operator >= (const this_type& other) const; | |||
inline reference operator * () const; | |||
inline pointer operator -> () const; | |||
inline this_type& operator ++ (); | |||
inline this_type& operator -- (); | |||
inline this_type operator ++ (int); | |||
inline this_type operator -- (int); | |||
inline this_type& operator += (difference_type diff); | |||
inline this_type& operator -= (difference_type diff); | |||
inline this_type operator + (difference_type diff) const; | |||
inline this_type operator - (difference_type diff) const; | |||
inline difference_type operator - (const this_type& other) const; | |||
inline this_type operator [] (difference_type diff); | |||
inline iterator_tpl(const row& p_row, ssize_t index, ssize_t direction); | |||
inline iterator_tpl(const this_type& other); | |||
}; | |||
public: | |||
using iterator_type = iterator_tpl<field>; | |||
using const_iterator_type = iterator_tpl<const field>; | |||
static constexpr size_t npos = std::numeric_limits<size_t>::max(); | |||
private: | |||
const result& _result; | |||
mutable unsigned long* _lengths; | |||
public: | |||
inline const column_vector& columns () const; | |||
inline unsigned int size () const; | |||
inline iterator_type begin () const; | |||
inline iterator_type end () const; | |||
inline const_iterator_type cbegin () const; | |||
inline const_iterator_type cend () const; | |||
inline iterator_type rbegin () const; | |||
inline iterator_type rend () const; | |||
inline const_iterator_type crbegin () const; | |||
inline const_iterator_type crend () const; | |||
size_t find (const std::string& name) const; | |||
field at (size_t i) const; | |||
field at (const std::string name) const; | |||
inline field operator[] (size_t i) const; | |||
inline field operator[] (const std::string& name) const; | |||
inline row(const result& p_result, MYSQL_ROW p_row); | |||
}; | |||
} |
@@ -0,0 +1,54 @@ | |||
#pragma once | |||
#include <string> | |||
#include <vector> | |||
#include <mariadb/config.h> | |||
#include <mariadb/forward/connection.h> | |||
#include <mariadb/forward/statement.h> | |||
namespace mariadb | |||
{ | |||
struct statement | |||
{ | |||
public: | |||
static constexpr size_t npos = std::numeric_limits<size_t>::max(); | |||
private: | |||
struct parameter | |||
{ | |||
bool has_value { false }; | |||
bool unescaped { false }; | |||
std::string value; | |||
}; | |||
private: | |||
mutable bool _changed; | |||
mutable std::string _query; | |||
mutable const connection* _connection; | |||
std::vector<std::string> _code; | |||
std::vector<std::pair<std::string, parameter>> _parameters; | |||
void parse(const std::string& query); | |||
void build(const connection& con) const; | |||
public: | |||
inline void assign (const std::string& query); | |||
inline const std::string& query (const connection& con) const; | |||
inline size_t find (const std::string& param); | |||
inline void set_null(const std::string& param); | |||
inline void set_null(size_t index); | |||
inline void clear (); | |||
template<class T> | |||
inline void set(const std::string& param, const T& value); | |||
template<class T> | |||
inline void set(size_t index, const T& value); | |||
inline statement(); | |||
inline statement(const std::string& query); | |||
}; | |||
} |
@@ -0,0 +1,28 @@ | |||
#pragma once | |||
#include <mariadb/config.h> | |||
#include <mariadb/enums.h> | |||
#include <mariadb/forward/connection.h> | |||
#include <mariadb/forward/statement.h> | |||
#include <mariadb/forward/transaction.h> | |||
namespace mariadb | |||
{ | |||
struct transaction | |||
{ | |||
private: | |||
connection& _connection; | |||
bool _closed; | |||
inline void begin(); | |||
public: | |||
inline void commit(); | |||
inline void rollback(); | |||
inline transaction(connection& connection); | |||
inline ~transaction(); | |||
}; | |||
} |
@@ -0,0 +1,29 @@ | |||
# Initialize ###################################################################################### | |||
Include ( cotire OPTIONAL ) | |||
Include ( pedantic OPTIONAL ) | |||
Set ( CMAKE_CXX_STANDARD 17 ) | |||
Set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PEDANTIC_C_FLAGS}" ) | |||
Set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PEDANTIC_CXX_FLAGS}" ) | |||
# Dependencies #################################################################################### | |||
Find_Package ( cpputils REQUIRED ) | |||
# Project: mariadb ################################################################################ | |||
Project ( mariadb VERSION 1.0.0.0 LANGUAGES CXX ) | |||
File ( GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | |||
Add_Library ( mariadb ${SOURCE_FILES} ) | |||
Target_Include_Directories ( | |||
mariadb | |||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include | |||
) | |||
Target_Link_Libraries ( | |||
mariadb | |||
cpputils | |||
) | |||
If ( __COTIRE_INCLUDED ) | |||
Cotire ( mariadb ) | |||
EndIf ( ) |
@@ -0,0 +1,29 @@ | |||
#include <mariadb/exception.h> | |||
#include <cpputils/misc/enum.h> | |||
#include <cpputils/misc/string.h> | |||
using namespace ::mariadb; | |||
void exception::print_message(std::ostream& os) const | |||
{ | |||
os << message; | |||
if ( error != error_code::NoError | |||
|| !query.empty()) | |||
{ | |||
os << " ("; | |||
bool first = true; | |||
if (error != error_code::NoError) | |||
{ | |||
os << "error_code="; | |||
utl::to_string(os, error); | |||
first = false; | |||
} | |||
if (!query.empty()) | |||
{ | |||
if (!first) | |||
os << "; "; | |||
os << "Query=" << query; | |||
} | |||
os << ")"; | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
#include <mariadb/result.h> | |||
#include <mariadb/column.h> | |||
#include <mariadb/inline/row.inl> | |||
#include <mariadb/inline/result.inl> | |||
using namespace ::mariadb; | |||
row* result::next() | |||
{ | |||
auto r = mysql_fetch_row(handle()); | |||
if (r) | |||
{ | |||
++_rowindex; | |||
_row.reset(new row(*this, r)); | |||
} | |||
else | |||
_row.reset(); | |||
return _row.get(); | |||
} | |||
void result::update_columns() const | |||
{ | |||
auto f = mysql_fetch_fields(handle()); | |||
auto c = mysql_num_fields (handle()); | |||
_columns.clear(); | |||
_columns.reserve(c); | |||
for (size_t i = 0; i < c; ++i) | |||
_columns.emplace_back(f[i]); | |||
} | |||
result::~result() | |||
{ free(); } | |||
result_used::~result_used() | |||
{ while(next()); /* fetch rows until none is left */ } |
@@ -0,0 +1,46 @@ | |||
#include <mariadb/row.h> | |||
#include <mariadb/column.h> | |||
#include <mariadb/exception.h> | |||
#include <mariadb/inline/row.inl> | |||
#include <mariadb/inline/field.inl> | |||
#include <mariadb/inline/result.inl> | |||
using namespace ::mariadb; | |||
size_t row::find(const std::string& name) const | |||
{ | |||
auto& columns = _result.columns(); | |||
for (size_t i = 0; i < columns.size(); ++i) | |||
{ | |||
if (columns.at(i).name == name) | |||
return i; | |||
} | |||
for (size_t i = 0; i < columns.size(); ++i) | |||
{ | |||
if (columns.at(i).original_name == name) | |||
return i; | |||
} | |||
return npos; | |||
} | |||
field row::at(size_t i) const | |||
{ | |||
if (i >= size()) | |||
throw exception("row index out of range", error_code::UnknownError); | |||
if (!_lengths) | |||
{ | |||
_lengths = mysql_fetch_lengths(_result.handle()); | |||
if (!_lengths) | |||
throw exception("unble to fetch lenghts for row", error_code::UnknownError); | |||
} | |||
return field(*this, i, handle()[i], _lengths[i]); | |||
} | |||
field row::at(const std::string name) const | |||
{ | |||
auto i = find(name); | |||
if (i == npos) | |||
throw exception(std::string("unknown field name: ") + name, error_code::UnknownError); | |||
return at(i); | |||
} |
@@ -0,0 +1,84 @@ | |||
#include <mariadb/row.h> | |||
#include <mariadb/enums.h> | |||
#include <mariadb/column.h> | |||
#include <mariadb/exception.h> | |||
#include <mariadb/inline/statement.inl> | |||
#include <mariadb/inline/connection.inl> | |||
using namespace ::mariadb; | |||
void statement::parse(const std::string& query) | |||
{ | |||
auto c = query.c_str(); | |||
auto t = c; | |||
bool inParam = false; | |||
while (*c != '\0') | |||
{ | |||
switch (*c) | |||
{ | |||
case '?': | |||
if (inParam) | |||
_parameters.emplace_back(std::string(t, static_cast<std::string::size_type>(c - t)), parameter { false, false, std::string() }); | |||
else | |||
_code.emplace_back(t, c - t); | |||
inParam = !inParam; | |||
t = c + 1; | |||
break; | |||
case '!': | |||
if (!inParam) | |||
break; | |||
_parameters.emplace_back(std::string(t, static_cast<std::string::size_type>(c - t)), parameter { false, true, std::string() }); | |||
inParam = false; | |||
t = c + 1; | |||
break; | |||
} | |||
++c; | |||
} | |||
if (inParam) | |||
throw exception("unclosed parameter in statement", error_code::Unknown, query); | |||
if (c != t) | |||
_code.emplace_back(t, c - t); | |||
} | |||
void statement::build(const connection& con) const | |||
{ | |||
_connection = &con; | |||
std::ostringstream ss; | |||
size_t i = 0; | |||
if (std::abs(static_cast<ssize_t>(_code.size()) - static_cast<ssize_t>(_parameters.size())) > 1) | |||
throw exception("statement::build() - internal error: code and parameter size mismatch", error_code::Unknown); | |||
while ( (i >> 1) < _code.size() | |||
|| (i >> 1) < _parameters.size()) | |||
{ | |||
size_t idx = (i >> 1); | |||
if ((i & 1) == 0) | |||
{ | |||
if (idx >= _code.size()) | |||
break; | |||
ss << _code.at(i >> 1); | |||
} | |||
else | |||
{ | |||
if (idx >= _parameters.size()) | |||
break; | |||
auto& param = _parameters.at(i >> 1).second; | |||
if (param.has_value) | |||
{ | |||
if (param.unescaped) | |||
ss << param.value; | |||
else | |||
ss << "'" << con.escape(param.value) << "'"; | |||
} | |||
else | |||
{ | |||
if (!param.unescaped) | |||
ss << "null"; | |||
} | |||
} | |||
++i; | |||
} | |||
_changed = false; | |||
_query = ss.str(); | |||
} |
@@ -0,0 +1,30 @@ | |||
# Initialize ###################################################################################### | |||
Include ( cotire OPTIONAL ) | |||
Include ( pedantic OPTIONAL ) | |||
Include ( cmake_tests OPTIONAL ) | |||
Set ( CMAKE_CXX_STANDARD 17 ) | |||
Set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PEDANTIC_C_FLAGS}" ) | |||
Set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PEDANTIC_CXX_FLAGS}" ) | |||
# Project: test_mariadb ########################################################################### | |||
Project ( test_mariadb ) | |||
File ( GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | |||
Add_Executable ( test_mariadb EXCLUDE_FROM_ALL ${SOURCE_FILES} ) | |||
Target_Link_Libraries ( | |||
test_mariadb | |||
mariadb | |||
cpputils | |||
gtest | |||
gmock | |||
gmock_main | |||
pthread | |||
) | |||
If ( __COTIRE_INCLUDED ) | |||
Cotire ( test_mariadb ) | |||
EndIf ( ) | |||
If ( __CMAKE_TESTS_INCLUDED ) | |||
Add_CMake_Test ( tsoutils test_mariadb ) | |||
EndIf ( ) |
@@ -0,0 +1,910 @@ | |||
#include <memory> | |||
#include <type_traits> | |||
#include <gtest/gtest.h> | |||
#include <mariadb.h> | |||
#include "mock.h" | |||
using namespace ::testing; | |||
using namespace ::mariadb; | |||
/**********************************************************************************************************/ | |||
TEST(MariaDbTests, MariaDB_connect) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_init(nullptr)) | |||
.WillOnce(Return(reinterpret_cast<MYSQL*>(0x123))); | |||
EXPECT_CALL(mock, mysql_real_connect(reinterpret_cast<MYSQL*>(0x123), StrEq("testhost"), StrEq("testuser"), StrEq("password"), StrEq("database"), 3306, nullptr, 0)) | |||
.WillOnce(Invoke([](MYSQL *mysql, const char*, const char*, const char*, const char*, unsigned int, const char*, unsigned long){ | |||
return mysql; | |||
})); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x123))) | |||
.Times(1); | |||
auto con = database::connect("testhost", 3306, "testuser", "password", "database", client_flags::empty()); | |||
EXPECT_EQ(reinterpret_cast<MYSQL*>(0x123), con.handle()); | |||
} | |||
TEST(MariaDbTests, MariaDB_errorCode) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(reinterpret_cast<MYSQL*>(0x123))) | |||
.WillOnce(Return(1000)); | |||
auto ret = database::error_code(reinterpret_cast<MYSQL*>(0x123)); | |||
EXPECT_EQ(error_code::ErrorFirst, ret); | |||
} | |||
TEST(MariaDbTests, MariaDB_errorMessage) | |||
{ | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
std::string msg("test"); | |||
EXPECT_CALL(mock, mysql_error(reinterpret_cast<MYSQL*>(0x123))) | |||
.WillOnce(Return(msg.data())); | |||
auto ret = database::error_msg(reinterpret_cast<MYSQL*>(0x123)); | |||
EXPECT_EQ(msg, ret); | |||
} | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_error(reinterpret_cast<MYSQL*>(0x123))) | |||
.WillOnce(Return(nullptr)); | |||
auto ret = database::error_msg(reinterpret_cast<MYSQL*>(0x123)); | |||
EXPECT_EQ(std::string(), ret); | |||
} | |||
} | |||
/**********************************************************************************************************/ | |||
TEST(MariaDbTests, Connection_fieldcount) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_field_count(reinterpret_cast<MYSQL*>(0x5514))) | |||
.WillOnce(Return(5)); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x5514))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x5514)); | |||
auto ret = con.fieldcount(); | |||
EXPECT_EQ(5, ret); | |||
} | |||
TEST(MariaDbTests, Connection_escape) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_real_escape_string(reinterpret_cast<MYSQL*>(0x5514), _, StrEq("'teststring'"), 12)) | |||
.WillOnce(DoAll( | |||
WithArgs<1>(Invoke([](char* str){ | |||
memcpy(str, "\\'teststring\\'", 14); | |||
})), | |||
Return(14))); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x5514))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x5514)); | |||
auto ret = con.escape("'teststring'"); | |||
EXPECT_EQ(std::string("\\'teststring\\'"), ret); | |||
} | |||
/**********************************************************************************************************/ | |||
TEST(MariaDbTests, Connection_execute_queryFailed) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(_)).Times(AnyNumber()); | |||
EXPECT_CALL(mock, mysql_error(_)).Times(AnyNumber()); | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_real_query(reinterpret_cast<MYSQL*>(0x6818), StrEq("SELECT * FROM blubb"), 19)) | |||
.WillOnce(Return(1)); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x6818))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x6818)); | |||
EXPECT_THROW(con.execute("SELECT * FROM blubb"), ::mariadb::exception); | |||
} | |||
TEST(MariaDbTests, Connection_execute_storeResultFailed_fieldCountGreaterZero) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(_)).Times(AnyNumber()); | |||
EXPECT_CALL(mock, mysql_error(_)).Times(AnyNumber()); | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_real_query(reinterpret_cast<MYSQL*>(0x6818), StrEq("SELECT * FROM blubb"), 19)) | |||
.WillOnce(Return(0)); | |||
EXPECT_CALL(mock, mysql_store_result(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(nullptr)); | |||
EXPECT_CALL(mock, mysql_field_count(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(5)); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x6818))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x6818)); | |||
EXPECT_THROW(con.execute("SELECT * FROM blubb"), ::mariadb::exception); | |||
} | |||
TEST(MariaDbTests, Connection_execute_storeResultFailed_fieldCountIsZero) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(_)).Times(AnyNumber()); | |||
EXPECT_CALL(mock, mysql_error(_)).Times(AnyNumber()); | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_real_query(reinterpret_cast<MYSQL*>(0x6818), StrEq("SELECT * FROM blubb"), 19)) | |||
.WillOnce(Return(0)); | |||
EXPECT_CALL(mock, mysql_store_result(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(nullptr)); | |||
EXPECT_CALL(mock, mysql_field_count(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(0)); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x6818))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x6818)); | |||
con.execute("SELECT * FROM blubb"); | |||
ASSERT_FALSE(static_cast<bool>(con.result())); | |||
} | |||
TEST(MariaDbTests, Connection_execute_success) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(_)).Times(AnyNumber()); | |||
EXPECT_CALL(mock, mysql_error(_)).Times(AnyNumber()); | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_real_query(reinterpret_cast<MYSQL*>(0x6818), StrEq("SELECT * FROM blubb"), 19)) | |||
.WillOnce(Return(0)); | |||
EXPECT_CALL(mock, mysql_store_result(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(reinterpret_cast<MYSQL_RES*>(0x8888))); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x8888))) | |||
.Times(1); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x6818))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x6818)); | |||
con.execute("SELECT * FROM blubb"); | |||
ASSERT_TRUE(static_cast<bool>(con.result())); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_RES*>(0x8888), con.result()->handle()); | |||
} | |||
/**********************************************************************************************************/ | |||
TEST(MariaDbTests, Connection_executeStored_queryFailed) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(_)).Times(AnyNumber()); | |||
EXPECT_CALL(mock, mysql_error(_)).Times(AnyNumber()); | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_real_query(reinterpret_cast<MYSQL*>(0x6818), StrEq("SELECT * FROM blubb"), 19)) | |||
.WillOnce(Return(1)); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x6818))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x6818)); | |||
EXPECT_THROW(con.execute_stored("SELECT * FROM blubb"), ::mariadb::exception); | |||
} | |||
TEST(MariaDbTests, Connection_executeStored_storeResultFailed_fieldCountGreaterZero) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(_)).Times(AnyNumber()); | |||
EXPECT_CALL(mock, mysql_error(_)).Times(AnyNumber()); | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_real_query(reinterpret_cast<MYSQL*>(0x6818), StrEq("SELECT * FROM blubb"), 19)) | |||
.WillOnce(Return(0)); | |||
EXPECT_CALL(mock, mysql_store_result(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(nullptr)); | |||
EXPECT_CALL(mock, mysql_field_count(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(5)); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x6818))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x6818)); | |||
EXPECT_THROW(con.execute_stored("SELECT * FROM blubb"), ::mariadb::exception); | |||
} | |||
TEST(MariaDbTests, Connection_executeStored_storeResultFailed_fieldCountIsZero) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(_)).Times(AnyNumber()); | |||
EXPECT_CALL(mock, mysql_error(_)).Times(AnyNumber()); | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_real_query(reinterpret_cast<MYSQL*>(0x6818), StrEq("SELECT * FROM blubb"), 19)) | |||
.WillOnce(Return(0)); | |||
EXPECT_CALL(mock, mysql_store_result(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(nullptr)); | |||
EXPECT_CALL(mock, mysql_field_count(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(0)); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x6818))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x6818)); | |||
con.execute_stored("SELECT * FROM blubb"); | |||
ASSERT_FALSE(static_cast<bool>(con.result())); | |||
} | |||
TEST(MariaDbTests, Connection_executeStored_success) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(_)).Times(AnyNumber()); | |||
EXPECT_CALL(mock, mysql_error(_)).Times(AnyNumber()); | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_real_query(reinterpret_cast<MYSQL*>(0x6818), StrEq("SELECT * FROM blubb"), 19)) | |||
.WillOnce(Return(0)); | |||
EXPECT_CALL(mock, mysql_store_result(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(reinterpret_cast<MYSQL_RES*>(0x8888))); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x8888))) | |||
.Times(1); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x6818))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x6818)); | |||
auto ret = con.execute_stored("SELECT * FROM blubb"); | |||
EXPECT_EQ (ret, con.result()); | |||
ASSERT_TRUE(static_cast<bool>(ret)); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_RES*>(0x8888), ret->handle()); | |||
} | |||
/**********************************************************************************************************/ | |||
TEST(MariaDbTests, Connection_executeUsed_queryFailed) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(_)).Times(AnyNumber()); | |||
EXPECT_CALL(mock, mysql_error(_)).Times(AnyNumber()); | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_real_query(reinterpret_cast<MYSQL*>(0x6818), StrEq("SELECT * FROM blubb"), 19)) | |||
.WillOnce(Return(1)); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x6818))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x6818)); | |||
EXPECT_THROW(con.execute_used("SELECT * FROM blubb"), ::mariadb::exception); | |||
} | |||
TEST(MariaDbTests, Connection_executeused_useResultFailed_fieldCountGreaterZero) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(_)).Times(AnyNumber()); | |||
EXPECT_CALL(mock, mysql_error(_)).Times(AnyNumber()); | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_real_query(reinterpret_cast<MYSQL*>(0x6818), StrEq("SELECT * FROM blubb"), 19)) | |||
.WillOnce(Return(0)); | |||
EXPECT_CALL(mock, mysql_use_result(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(nullptr)); | |||
EXPECT_CALL(mock, mysql_field_count(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(5)); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x6818))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x6818)); | |||
EXPECT_THROW(con.execute_used("SELECT * FROM blubb"), ::mariadb::exception); | |||
} | |||
TEST(MariaDbTests, Connection_executeUsed_useResultFailed_fieldCountIsZero) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(_)).Times(AnyNumber()); | |||
EXPECT_CALL(mock, mysql_error(_)).Times(AnyNumber()); | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_real_query(reinterpret_cast<MYSQL*>(0x6818), StrEq("SELECT * FROM blubb"), 19)) | |||
.WillOnce(Return(0)); | |||
EXPECT_CALL(mock, mysql_use_result(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(nullptr)); | |||
EXPECT_CALL(mock, mysql_field_count(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(0)); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x6818))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x6818)); | |||
con.execute_used("SELECT * FROM blubb"); | |||
ASSERT_FALSE(static_cast<bool>(con.result())); | |||
} | |||
TEST(MariaDbTests, Connection_executeUsed_success) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_errno(_)).Times(AnyNumber()); | |||
EXPECT_CALL(mock, mysql_error(_)).Times(AnyNumber()); | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_real_query(reinterpret_cast<MYSQL*>(0x6818), StrEq("SELECT * FROM blubb"), 19)) | |||
.WillOnce(Return(0)); | |||
EXPECT_CALL(mock, mysql_use_result(reinterpret_cast<MYSQL*>(0x6818))) | |||
.WillOnce(Return(reinterpret_cast<MYSQL_RES*>(0x8888))); | |||
EXPECT_CALL(mock, mysql_fetch_row(reinterpret_cast<MYSQL_RES*>(0x8888))) | |||
.WillOnce(Return(nullptr)); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x8888))) | |||
.Times(1); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x6818))) | |||
.Times(1); | |||
connection con(reinterpret_cast<MYSQL*>(0x6818)); | |||
auto ret = con.execute_used("SELECT * FROM blubb"); | |||
EXPECT_EQ (ret, con.result()); | |||
ASSERT_TRUE(static_cast<bool>(ret)); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_RES*>(0x8888), ret->handle()); | |||
} | |||
/**********************************************************************************************************/ | |||
TEST(MariaDbTests, Statement_set_validIndex) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
statement s("SELECT * FROM ?table?"); | |||
EXPECT_NO_THROW(s.set(0, "test")); | |||
} | |||
TEST(MariaDbTests, Statement_set_invalidIndex) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
statement s("SELECT * FROM ?table?"); | |||
EXPECT_THROW(s.set(4, "test"), ::mariadb::exception); | |||
} | |||
TEST(MariaDbTests, Statement_set_validName) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
statement s("SELECT * FROM ?table?"); | |||
EXPECT_NO_THROW(s.set("table", "test")); | |||
} | |||
TEST(MariaDbTests, Statement_set_invalidName) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
statement s("SELECT * FROM ?table?"); | |||
EXPECT_THROW(s.set("foo", "test"), ::mariadb::exception); | |||
} | |||
TEST(MariaDbTests, Statement_query) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
EXPECT_CALL(mock, mysql_real_escape_string(reinterpret_cast<MYSQL*>(0x123), _, StrEq("test"), 4)) | |||
.WillOnce(DoAll( | |||
WithArgs<1>(Invoke([](char* str){ | |||
memcpy(str, "test", 4); | |||
})), | |||
Return(4))); | |||
EXPECT_CALL(mock, mysql_close(reinterpret_cast<MYSQL*>(0x123))) | |||
.Times(1); | |||
connection c(reinterpret_cast<MYSQL*>(0x123)); | |||
statement s("SELECT * FROM ?table?"); | |||
s.set("table", "test"); | |||
auto ret = s.query(c); | |||
EXPECT_EQ(std::string("SELECT * FROM 'test'"), ret); | |||
} | |||
/**********************************************************************************************************/ | |||
TEST(MariaDbTests, Result_rowindex_next_current) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_fetch_row(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(reinterpret_cast<MYSQL_ROW>(0x15160))) | |||
.WillOnce(Return(reinterpret_cast<MYSQL_ROW>(0x15161))); | |||
EXPECT_CALL(mock, mysql_data_seek(reinterpret_cast<MYSQL_RES*>(0x51651), 0)) | |||
.Times(1); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
EXPECT_EQ(-1, result.rowindex()); | |||
auto row = result.next(); | |||
ASSERT_TRUE(static_cast<bool>(row)); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_ROW>(0x15160), row->handle()); | |||
EXPECT_EQ (0, result.rowindex()); | |||
row = result.next(); | |||
ASSERT_TRUE(static_cast<bool>(row)); | |||
EXPECT_EQ (reinterpret_cast<MYSQL_ROW>(0x15161), row->handle()); | |||
EXPECT_EQ (1, result.rowindex()); | |||
auto current = result.current(); | |||
EXPECT_EQ(row, current); | |||
result.rowindex(0); | |||
EXPECT_EQ(0, result.rowindex()); | |||
} | |||
TEST(MariaDbTests, Result_columncount) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_num_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(10)); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
auto ret = result.columncount(); | |||
EXPECT_EQ(10, ret); | |||
} | |||
TEST(MariaDbTests, Result_columns) | |||
{ | |||
static const std::string name0 ("index"); | |||
static const std::string name1 ("username"); | |||
static const std::string name2 ("password"); | |||
static const std::string table ("user"); | |||
static const std::string database ("database"); | |||
MYSQL_FIELD fields[3]; | |||
fields[0].name = const_cast<char*>(name0.c_str()); | |||
fields[0].org_name = const_cast<char*>(name0.c_str()); | |||
fields[0].table = const_cast<char*>(table.c_str()); | |||
fields[0].org_table = const_cast<char*>(table.c_str()); | |||
fields[0].db = const_cast<char*>(database.c_str()); | |||
fields[0].catalog = nullptr; | |||
fields[0].def = nullptr; | |||
fields[0].length = 32; | |||
fields[0].max_length = 2; | |||
fields[0].name_length = static_cast<unsigned int>(name0.size()); | |||
fields[0].org_name_length = static_cast<unsigned int>(name0.size()); | |||
fields[0].table_length = static_cast<unsigned int>(table.size()); | |||
fields[0].org_table_length = static_cast<unsigned int>(table.size()); | |||
fields[0].db_length = static_cast<unsigned int>(database.size()); | |||
fields[0].catalog_length = 0; | |||
fields[0].def_length = 0; | |||
fields[0].flags = 0; | |||
fields[0].decimals = 0; | |||
fields[0].charsetnr = 0; | |||
fields[0].type = MYSQL_TYPE_LONG; | |||
fields[0].extension = nullptr; | |||
fields[1].name = const_cast<char*>(name1.c_str()); | |||
fields[1].org_name = const_cast<char*>(name1.c_str()); | |||
fields[1].table = const_cast<char*>(table.c_str()); | |||
fields[1].org_table = const_cast<char*>(table.c_str()); | |||
fields[1].db = const_cast<char*>(database.c_str()); | |||
fields[1].catalog = nullptr; | |||
fields[1].def = nullptr; | |||
fields[1].length = 128; | |||
fields[1].max_length = 48; | |||
fields[1].name_length = static_cast<unsigned int>(name1.size()); | |||
fields[1].org_name_length = static_cast<unsigned int>(name1.size()); | |||
fields[1].table_length = static_cast<unsigned int>(table.size()); | |||
fields[1].org_table_length = static_cast<unsigned int>(table.size()); | |||
fields[1].db_length = static_cast<unsigned int>(database.size()); | |||
fields[1].catalog_length = 0; | |||
fields[1].def_length = 0; | |||
fields[1].flags = 0; | |||
fields[1].decimals = 0; | |||
fields[1].charsetnr = 0; | |||
fields[1].type = MYSQL_TYPE_STRING; | |||
fields[1].extension = nullptr; | |||
fields[2].name = const_cast<char*>(name2.c_str()); | |||
fields[2].org_name = const_cast<char*>(name2.c_str()); | |||
fields[2].table = const_cast<char*>(table.c_str()); | |||
fields[2].org_table = const_cast<char*>(table.c_str()); | |||
fields[2].db = const_cast<char*>(database.c_str()); | |||
fields[2].catalog = nullptr; | |||
fields[2].def = nullptr; | |||
fields[2].length = 128; | |||
fields[2].max_length = 42; | |||
fields[2].name_length = static_cast<unsigned int>(name2.size()); | |||
fields[2].org_name_length = static_cast<unsigned int>(name2.size()); | |||
fields[2].table_length = static_cast<unsigned int>(table.size()); | |||
fields[2].org_table_length = static_cast<unsigned int>(table.size()); | |||
fields[2].db_length = static_cast<unsigned int>(database.size()); | |||
fields[2].catalog_length = 0; | |||
fields[2].def_length = 0; | |||
fields[2].flags = 0; | |||
fields[2].decimals = 0; | |||
fields[2].charsetnr = 0; | |||
fields[2].type = MYSQL_TYPE_STRING; | |||
fields[2].extension = nullptr; | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_fetch_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(fields)); | |||
EXPECT_CALL(mock, mysql_num_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(3)); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
auto ret = result.columns(); | |||
ASSERT_EQ(3, ret.size()); | |||
EXPECT_EQ(name0, ret.at(0).name); | |||
EXPECT_EQ(name0, ret.at(0).original_name); | |||
EXPECT_EQ(table, ret.at(0).table); | |||
EXPECT_EQ(table, ret.at(0).original_table); | |||
EXPECT_EQ(database, ret.at(0).database); | |||
EXPECT_EQ(32, ret.at(0).length); | |||
EXPECT_EQ(2, ret.at(0).max_length); | |||
EXPECT_EQ(column_flags::empty(), ret.at(0).flags); | |||
EXPECT_EQ(0, ret.at(0).decimals); | |||
EXPECT_EQ(0, ret.at(0).charset_number); | |||
EXPECT_EQ(column_type::Long, ret.at(0).type); | |||
EXPECT_EQ(name1, ret.at(1).name); | |||
EXPECT_EQ(name1, ret.at(1).original_name); | |||
EXPECT_EQ(table, ret.at(1).table); | |||
EXPECT_EQ(table, ret.at(1).original_table); | |||
EXPECT_EQ(database, ret.at(1).database); | |||
EXPECT_EQ(128, ret.at(1).length); | |||
EXPECT_EQ(48, ret.at(1).max_length); | |||
EXPECT_EQ(column_flags::empty(), ret.at(1).flags); | |||
EXPECT_EQ(0, ret.at(1).decimals); | |||
EXPECT_EQ(0, ret.at(1).charset_number); | |||
EXPECT_EQ(column_type::String, ret.at(1).type); | |||
EXPECT_EQ(name2, ret.at(2).name); | |||
EXPECT_EQ(name2, ret.at(2).original_name); | |||
EXPECT_EQ(table, ret.at(2).table); | |||
EXPECT_EQ(table, ret.at(2).original_table); | |||
EXPECT_EQ(database, ret.at(2).database); | |||
EXPECT_EQ(128, ret.at(2).length); | |||
EXPECT_EQ(42, ret.at(2).max_length); | |||
EXPECT_EQ(column_flags::empty(), ret.at(2).flags); | |||
EXPECT_EQ(0, ret.at(2).decimals); | |||
EXPECT_EQ(0, ret.at(2).charset_number); | |||
EXPECT_EQ(column_type::String, ret.at(2).type); | |||
} | |||
/**********************************************************************************************************/ | |||
TEST(MariaDbTests, StoredResult_rowoffset) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_row_tell(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(reinterpret_cast<MYSQL_ROW_OFFSET>(0))); | |||
EXPECT_CALL(mock, mysql_row_seek(reinterpret_cast<MYSQL_RES*>(0x51651), reinterpret_cast<MYSQL_ROW_OFFSET>(4))) | |||
.WillOnce(Return(reinterpret_cast<MYSQL_ROW_OFFSET>(0))); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
auto offset = result.rowoffset(); | |||
EXPECT_EQ(reinterpret_cast<MYSQL_ROW_OFFSET>(0), offset); | |||
result.rowoffset(reinterpret_cast<MYSQL_ROW_OFFSET>(4)); | |||
} | |||
TEST(MariaDbTests, StoredResult_rowcount) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_num_rows(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(100)); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
auto ret = result.rowcount(); | |||
EXPECT_EQ(100, ret); | |||
} | |||
/**********************************************************************************************************/ | |||
TEST(MariaDbTests, UsedResult_dtor) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_fetch_row(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(reinterpret_cast<MYSQL_ROW>(0x0001))) | |||
.WillOnce(Return(reinterpret_cast<MYSQL_ROW>(0x0002))) | |||
.WillOnce(Return(reinterpret_cast<MYSQL_ROW>(0x0003))) | |||
.WillOnce(Return(reinterpret_cast<MYSQL_ROW>(0x0004))) | |||
.WillOnce(Return(nullptr)); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_used result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
} | |||
/**********************************************************************************************************/ | |||
static const char* RowData[3] = | |||
{ | |||
"2", | |||
"bergmann89", | |||
"secret" | |||
}; | |||
static unsigned long RowLengths[3] = | |||
{ | |||
1, | |||
10, | |||
6 | |||
}; | |||
TEST(MariaDbTests, Row_columns) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_fetch_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(nullptr)); | |||
EXPECT_CALL(mock, mysql_num_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(0)); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
row row(result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
row.columns(); | |||
} | |||
TEST(MariaDbTests, Row_size) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_num_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(3)); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
row row(result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
auto ret = row.size(); | |||
EXPECT_EQ(3u, ret); | |||
} | |||
TEST(MariaDbTests, Row_at_invalidIndex) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_num_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(3)); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
row row(result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
EXPECT_THROW(row.at(3), ::mariadb::exception); | |||
} | |||
TEST(MariaDbTests, Row_at_validIndex) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_num_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(3)); | |||
EXPECT_CALL(mock, mysql_fetch_lengths(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(&RowLengths[0])); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
row row(result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
EXPECT_NO_THROW(row.at(1)); | |||
} | |||
static const std::string RowDataName0("index"); | |||
static const std::string RowDataName1("username"); | |||
static const std::string RowDataName2("password"); | |||
TEST(MariaDbTests, Row_at_invalidName) | |||
{ | |||
MYSQL_FIELD fields[3]; | |||
memset(&fields[0], 0, sizeof(fields)); | |||
fields[0].name = const_cast<char*>(RowDataName0.c_str()); | |||
fields[0].name_length = static_cast<unsigned int>(RowDataName0.size()); | |||
fields[1].name = const_cast<char*>(RowDataName1.c_str()); | |||
fields[1].name_length = static_cast<unsigned int>(RowDataName1.size()); | |||
fields[2].name = const_cast<char*>(RowDataName2.c_str()); | |||
fields[2].name_length = static_cast<unsigned int>(RowDataName2.size()); | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_fetch_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(fields)); | |||
EXPECT_CALL(mock, mysql_num_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(3)); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
row row(result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
EXPECT_THROW(row.at("blubb"), ::mariadb::exception); | |||
} | |||
TEST(MariaDbTests, Row_at_validName) | |||
{ | |||
MYSQL_FIELD fields[3]; | |||
memset(&fields[0], 0, sizeof(fields)); | |||
fields[0].name = const_cast<char*>(RowDataName0.c_str()); | |||
fields[0].name_length = static_cast<unsigned int>(RowDataName0.size()); | |||
fields[1].name = const_cast<char*>(RowDataName1.c_str()); | |||
fields[1].name_length = static_cast<unsigned int>(RowDataName1.size()); | |||
fields[2].name = const_cast<char*>(RowDataName2.c_str()); | |||
fields[2].name_length = static_cast<unsigned int>(RowDataName2.size()); | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_fetch_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(fields)); | |||
EXPECT_CALL(mock, mysql_num_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillRepeatedly(Return(3)); | |||
EXPECT_CALL(mock, mysql_fetch_lengths(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillOnce(Return(&RowLengths[0])); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
row row(result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
EXPECT_NO_THROW(row.at("username")); | |||
} | |||
TEST(MariaDbTests, Row_iterator) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_num_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillRepeatedly(Return(3)); | |||
EXPECT_CALL(mock, mysql_fetch_lengths(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillRepeatedly(Return(&RowLengths[0])); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
row row(result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
auto it = row.begin(); | |||
ASSERT_TRUE(it != row.end()); | |||
++it; | |||
ASSERT_TRUE(it != row.end()); | |||
++it; | |||
ASSERT_TRUE(it != row.end()); | |||
++it; | |||
ASSERT_TRUE(it == row.end()); | |||
} | |||
TEST(MariaDbTests, Row_const_iterator) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_num_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillRepeatedly(Return(3)); | |||
EXPECT_CALL(mock, mysql_fetch_lengths(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillRepeatedly(Return(&RowLengths[0])); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
row row(result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
auto it = row.cbegin(); | |||
ASSERT_TRUE(it != row.cend()); | |||
++it; | |||
ASSERT_TRUE(it != row.cend()); | |||
++it; | |||
ASSERT_TRUE(it != row.cend()); | |||
++it; | |||
ASSERT_TRUE(it == row.cend()); | |||
} | |||
TEST(MariaDbTests, Row_reverse_iterator) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_num_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillRepeatedly(Return(3)); | |||
EXPECT_CALL(mock, mysql_fetch_lengths(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillRepeatedly(Return(&RowLengths[0])); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
row row(result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
auto it = row.rbegin(); | |||
ASSERT_TRUE(it != row.rend()); | |||
++it; | |||
ASSERT_TRUE(it != row.rend()); | |||
++it; | |||
ASSERT_TRUE(it != row.rend()); | |||
++it; | |||
ASSERT_TRUE(it == row.rend()); | |||
} | |||
TEST(MariaDbTests, Row_const_reverse_iterator) | |||
{ | |||
StrictMock<MariaDbMock> mock; | |||
InSequence seq; | |||
EXPECT_CALL(mock, mysql_num_fields(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillRepeatedly(Return(3)); | |||
EXPECT_CALL(mock, mysql_fetch_lengths(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.WillRepeatedly(Return(&RowLengths[0])); | |||
EXPECT_CALL(mock, mysql_free_result(reinterpret_cast<MYSQL_RES*>(0x51651))) | |||
.Times(1); | |||
result_stored result(reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
row row(result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
auto it = row.crbegin(); | |||
ASSERT_TRUE(it != row.crend()); | |||
++it; | |||
ASSERT_TRUE(it != row.crend()); | |||
++it; | |||
ASSERT_TRUE(it != row.crend()); | |||
++it; | |||
ASSERT_TRUE(it == row.crend()); | |||
} | |||
/**********************************************************************************************************/ | |||
TEST(MariaDbTests, Field_index) | |||
{ | |||
mariadb::result_stored result (reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
mariadb::row row (result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
mariadb::field field (row, 1, RowData[1], RowLengths[1]); | |||
EXPECT_EQ(1, field.index()); | |||
} | |||
TEST(MariaDbTests, Field_isNull) | |||
{ | |||
mariadb::result_stored result (reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
mariadb::row row (result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
mariadb::field field0 (row, 1, nullptr, 0); | |||
mariadb::field field1 (row, 1, "", 0); | |||
mariadb::field field2 (row, 1, "asd", 3); | |||
EXPECT_TRUE (field0.is_null()); | |||
EXPECT_FALSE(field1.is_null()); | |||
EXPECT_FALSE(field2.is_null()); | |||
} | |||
TEST(MariaDbTests, Field_isEmpty) | |||
{ | |||
mariadb::result_stored result (reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
mariadb::row row (result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
mariadb::field field0 (row, 1, nullptr, 0); | |||
mariadb::field field1 (row, 1, "", 0); | |||
mariadb::field field2 (row, 1, "asd", 3); | |||
EXPECT_TRUE (field0.is_empty()); | |||
EXPECT_TRUE (field1.is_empty()); | |||
EXPECT_FALSE(field2.is_empty()); | |||
} | |||
TEST(MariaDbTests, Field_data) | |||
{ | |||
static const char* data = "test"; | |||
mariadb::result_stored result (reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
mariadb::row row (result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
mariadb::field field (row, 1, data, 4); | |||
EXPECT_EQ(data, field.data()); | |||
} | |||
TEST(MariaDbTests, Field_size) | |||
{ | |||
static const char* data = "test"; | |||
mariadb::result_stored result (reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
mariadb::row row (result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
mariadb::field field (row, 1, data, 4); | |||
EXPECT_EQ(4, field.size()); | |||
} | |||
TEST(MariaDbTests, Field_implicit_bool_cast) | |||
{ | |||
mariadb::result_stored result (reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
mariadb::row row (result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
mariadb::field field0 (row, 1, nullptr, 0); | |||
mariadb::field field1 (row, 1, "", 0); | |||
mariadb::field field2 (row, 1, "asd", 3); | |||
EXPECT_FALSE(static_cast<bool>(field0)); | |||
EXPECT_FALSE(static_cast<bool>(field1)); | |||
EXPECT_TRUE (static_cast<bool>(field2)); | |||
} | |||
TEST(MariaDbTests, Field_get) | |||
{ | |||
mariadb::result_stored result (reinterpret_cast<MYSQL_RES*>(0x51651)); | |||
mariadb::row row (result, const_cast<MYSQL_ROW>(&RowData[0])); | |||
mariadb::field field0 (row, 1, "123", 3); | |||
mariadb::field field1 (row, 1, "asd", 3); | |||
EXPECT_EQ(123, field0.get<int>()); | |||
EXPECT_EQ(std::string("asd"), field1.get<std::string>()); | |||
} |
@@ -0,0 +1,77 @@ | |||
#include "mock.h" | |||
MariaDbMock* mariadb_mock_instance; | |||
void MariaDbMock::setInstance(MariaDbMock* value) | |||
{ | |||
mariadb_mock_instance = value; | |||
} | |||
void MariaDbMock::clearInstance(MariaDbMock* value) | |||
{ | |||
if (mariadb_mock_instance == value) | |||
mariadb_mock_instance = nullptr; | |||
} | |||
my_ulonglong STDCALL mysql_num_rows (MYSQL_RES *res) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_num_rows(res) : 0); } | |||
unsigned int STDCALL mysql_num_fields (MYSQL_RES *res) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_num_fields(res) : 0); } | |||
MYSQL_ROWS* STDCALL mysql_row_tell (MYSQL_RES *res) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_row_tell(res) : nullptr); } | |||
void STDCALL mysql_free_result (MYSQL_RES *res) | |||
{ if (mariadb_mock_instance) mariadb_mock_instance->mysql_free_result(res); } | |||
MYSQL_ROW_OFFSET STDCALL mysql_row_seek (MYSQL_RES *res, MYSQL_ROW_OFFSET offset) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_row_seek(res, offset) : nullptr); } | |||
void STDCALL mysql_data_seek (MYSQL_RES *res, unsigned long long offset) | |||
{ if (mariadb_mock_instance) mariadb_mock_instance->mysql_data_seek(res, offset); } | |||
unsigned long* STDCALL mysql_fetch_lengths (MYSQL_RES *res) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_fetch_lengths(res) : nullptr); } | |||
MYSQL_ROW STDCALL mysql_fetch_row (MYSQL_RES *res) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_fetch_row(res) : nullptr); } | |||
MYSQL_FIELD* STDCALL mysql_fetch_fields (MYSQL_RES *res) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_fetch_fields(res) : nullptr); } | |||
int STDCALL mysql_real_query (MYSQL *mysql, const char *q, unsigned long length) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_real_query(mysql, q, length) : 0); } | |||
unsigned int STDCALL mysql_errno (MYSQL *mysql) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_errno(mysql) : 0); } | |||
const char* STDCALL mysql_error (MYSQL *mysql) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_error(mysql) : nullptr); } | |||
MYSQL_RES* STDCALL mysql_store_result (MYSQL *mysql) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_store_result(mysql) : nullptr); } | |||
MYSQL_RES* STDCALL mysql_use_result (MYSQL *mysql) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_use_result(mysql) : nullptr); } | |||
unsigned int STDCALL mysql_field_count (MYSQL *mysql) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_field_count(mysql) : 0); } | |||
my_ulonglong STDCALL mysql_affected_rows (MYSQL *mysql) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_affected_rows(mysql) : 0); } | |||
my_ulonglong STDCALL mysql_insert_id (MYSQL *mysql) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_insert_id(mysql) : 0); } | |||
unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_real_escape_string(mysql, to, from, length) : 0); } | |||
void STDCALL mysql_close (MYSQL *mysql) | |||
{ if (mariadb_mock_instance) mariadb_mock_instance->mysql_close(mysql); } | |||
MYSQL* STDCALL mysql_real_connect (MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_real_connect(mysql, host, user, passwd, db, port, unix_socket, clientflag) : nullptr); } | |||
MYSQL* STDCALL mysql_init (MYSQL *mysql) | |||
{ return (mariadb_mock_instance ? mariadb_mock_instance->mysql_init(mysql) : nullptr); } |
@@ -0,0 +1,121 @@ | |||
#pragma once | |||
#include <gmock/gmock.h> | |||
#include <mariadb/errmsg.h> | |||
#include <mariadb/mysqld_error.h> | |||
#include <mariadb/mysql.h> | |||
#define MARIADB_MOCK | |||
#if !defined(_WIN32) | |||
#define STDCALL | |||
#else | |||
#define STDCALL __stdcall | |||
#endif | |||
#define NOT_NULL_FLAG 1 /* field can't be NULL */ | |||
#define PRI_KEY_FLAG 2 /* field is part of a primary key */ | |||
#define UNIQUE_KEY_FLAG 4 /* field is part of a unique key */ | |||
#define MULTIPLE_KEY_FLAG 8 /* field is part of a key */ | |||
#define BLOB_FLAG 16 /* field is a blob */ | |||
#define UNSIGNED_FLAG 32 /* field is unsigned */ | |||
#define ZEROFILL_FLAG 64 /* field is zerofill */ | |||
#define BINARY_FLAG 128 | |||
#define ENUM_FLAG 256 /* field is an enum */ | |||
#define AUTO_INCREMENT_FLAG 512 /* field is a autoincrement field */ | |||
#define TIMESTAMP_FLAG 1024 /* field is a timestamp */ | |||
#define SET_FLAG 2048 /* field is a set */ | |||
#define NO_DEFAULT_VALUE_FLAG 4096 /* field doesn't have default value */ | |||
#define ON_UPDATE_NOW_FLAG 8192 /* field is set to NOW on UPDATE */ | |||
#define NUM_FLAG 32768 /* field is num (for clients) */ | |||
#define PART_KEY_FLAG 16384 /* Intern; Part of some key */ | |||
#define GROUP_FLAG 32768 /* Intern: Group field */ | |||
#define UNIQUE_FLAG 65536 /* Intern: Used by sql_yacc */ | |||
#define CLIENT_MYSQL 1 | |||
#define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */ | |||
#define CLIENT_LONG_FLAG 4 /* Get all column flags */ | |||
#define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */ | |||
#define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */ | |||
#define CLIENT_COMPRESS 32 /* Can use compression protocol */ | |||
#define CLIENT_ODBC 64 /* Odbc client */ | |||
#define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */ | |||
#define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */ | |||
#define CLIENT_INTERACTIVE 1024 /* This is an interactive client */ | |||
#define CLIENT_SSL 2048 /* Switch to SSL after handshake */ | |||
#define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ | |||
#define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */ | |||
#define CLIENT_PROTOCOL_41 512 | |||
#define CLIENT_RESERVED 16384 | |||
#define CLIENT_SECURE_CONNECTION 32768 | |||
#define CLIENT_MULTI_STATEMENTS (1UL << 16) | |||
#define CLIENT_MULTI_RESULTS (1UL << 17) | |||
#define CLIENT_PS_MULTI_RESULTS (1UL << 18) | |||
#define CLIENT_PLUGIN_AUTH (1UL << 19) | |||
#define CLIENT_CONNECT_ATTRS (1UL << 20) | |||
#define CLIENT_SESSION_TRACKING (1UL << 23) | |||
#define CLIENT_PROGRESS (1UL << 29) | |||
#define CLIENT_PROGRESS_OBSOLETE CLIENT_PROGRESS | |||
#define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30) | |||
#define CLIENT_REMEMBER_OPTIONS (1UL << 31) | |||
struct MariaDbMock | |||
{ | |||
private: | |||
static void setInstance(MariaDbMock* value); | |||
static void clearInstance(MariaDbMock* value); | |||
public: | |||
MOCK_METHOD1(mysql_num_rows, my_ulonglong (MYSQL_RES *res)); | |||
MOCK_METHOD1(mysql_num_fields, unsigned int (MYSQL_RES *res)); | |||
MOCK_METHOD1(mysql_row_tell, MYSQL_ROWS* (MYSQL_RES *res)); | |||
MOCK_METHOD1(mysql_free_result, void (MYSQL_RES *res)); | |||
MOCK_METHOD2(mysql_row_seek, MYSQL_ROW_OFFSET(MYSQL_RES *res, MYSQL_ROW_OFFSET)); | |||
MOCK_METHOD2(mysql_data_seek, void (MYSQL_RES *res, unsigned long long offset)); | |||
MOCK_METHOD1(mysql_fetch_lengths, unsigned long* (MYSQL_RES *res)); | |||
MOCK_METHOD1(mysql_fetch_row, MYSQL_ROW (MYSQL_RES *res)); | |||
MOCK_METHOD1(mysql_fetch_fields, MYSQL_FIELD* (MYSQL_RES *res)); | |||
MOCK_METHOD3(mysql_real_query, int (MYSQL *mysql, const char *q, unsigned long length)); | |||
MOCK_METHOD1(mysql_errno, unsigned int (MYSQL *mysql)); | |||
MOCK_METHOD1(mysql_error, const char* (MYSQL *mysql)); | |||
MOCK_METHOD1(mysql_store_result, MYSQL_RES* (MYSQL *mysql)); | |||
MOCK_METHOD1(mysql_use_result, MYSQL_RES* (MYSQL *mysql)); | |||
MOCK_METHOD1(mysql_field_count, unsigned int (MYSQL *mysql)); | |||
MOCK_METHOD1(mysql_affected_rows, my_ulonglong (MYSQL *mysql)); | |||
MOCK_METHOD1(mysql_insert_id, my_ulonglong (MYSQL *mysql)); | |||
MOCK_METHOD4(mysql_real_escape_string, unsigned long (MYSQL *mysql, char *to, const char *from, unsigned long length)); | |||
MOCK_METHOD1(mysql_close, void (MYSQL *mysql)); | |||
MOCK_METHOD8(mysql_real_connect, MYSQL* (MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag)); | |||
MOCK_METHOD1(mysql_init, MYSQL* (MYSQL *mysql)); | |||
MariaDbMock() | |||
{ setInstance(this); } | |||
~MariaDbMock() | |||
{ clearInstance(this); } | |||
}; | |||
my_ulonglong STDCALL mysql_num_rows (MYSQL_RES *res); | |||
unsigned int STDCALL mysql_num_fields (MYSQL_RES *res); | |||
MYSQL_ROWS* STDCALL mysql_row_tell (MYSQL_RES *res); | |||
void STDCALL mysql_free_result (MYSQL_RES *res); | |||
MYSQL_ROW_OFFSET STDCALL mysql_row_seek (MYSQL_RES *res, MYSQL_ROW_OFFSET); | |||
void STDCALL mysql_data_seek (MYSQL_RES *res, unsigned long long offset); | |||
unsigned long* STDCALL mysql_fetch_lengths (MYSQL_RES *res); | |||
MYSQL_ROW STDCALL mysql_fetch_row (MYSQL_RES *res); | |||
MYSQL_FIELD* STDCALL mysql_fetch_fields (MYSQL_RES *res); | |||
int STDCALL mysql_real_query (MYSQL *mysql, const char *q, unsigned long length); | |||
unsigned int STDCALL mysql_errno (MYSQL *mysql); | |||
const char* STDCALL mysql_error (MYSQL *mysql); | |||
MYSQL_RES* STDCALL mysql_store_result (MYSQL *mysql); | |||
MYSQL_RES* STDCALL mysql_use_result (MYSQL *mysql); | |||
unsigned int STDCALL mysql_field_count (MYSQL *mysql); | |||
my_ulonglong STDCALL mysql_affected_rows (MYSQL *mysql); | |||
my_ulonglong STDCALL mysql_insert_id (MYSQL *mysql); | |||
unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); | |||
void STDCALL mysql_close (MYSQL *mysql); | |||
MYSQL* STDCALL mysql_real_connect (MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); | |||
MYSQL* STDCALL mysql_init (MYSQL *mysql); |