2018-12-14 16:34:18 -06:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include "../Lib/mysql/include/mysql.h"
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// clean up functors
|
|
|
|
|
|
|
|
|
|
struct mysql_close_func_t
|
|
|
|
|
{
|
|
|
|
|
void operator()(MYSQL* s) { if (s) mysql_close(s); }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct mysql_stmt_delete_func_t
|
|
|
|
|
{
|
|
|
|
|
void operator()(MYSQL_STMT* s) { if (s) mysql_stmt_close(s); }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// smart pointer aliases
|
|
|
|
|
|
|
|
|
|
using mysql_ptr_t = std::unique_ptr< MYSQL_STMT, mysql_close_func_t >;
|
|
|
|
|
using mysql_stmt_ptr_t = std::unique_ptr< MYSQL_STMT, mysql_stmt_delete_func_t >;
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// statement / parameter helpers
|
|
|
|
|
|
|
|
|
|
class mysql_param_list_base;
|
|
|
|
|
class mysql_statement_base;
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// parameter manipulation
|
|
|
|
|
|
|
|
|
|
class mysql_param_list_base
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
MYSQL_BIND *m_params_ptr;
|
|
|
|
|
int m_count;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
mysql_param_list_base(MYSQL_BIND *params, int count)
|
|
|
|
|
: m_params_ptr(params), m_count(count)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
inline virtual void bind(int index, bool &val)
|
|
|
|
|
{
|
|
|
|
|
bind(index, &val);
|
|
|
|
|
}
|
|
|
|
|
inline virtual void bind(int index, bool *val)
|
|
|
|
|
{
|
|
|
|
|
_ASSERT(index < m_count);
|
|
|
|
|
m_params_ptr[index].buffer = val;
|
|
|
|
|
m_params_ptr[index].buffer_type = MYSQL_TYPE_BIT;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-08 12:25:04 -06:00
|
|
|
// short
|
|
|
|
|
inline virtual void bind(int index, int16_t &val)
|
|
|
|
|
{
|
|
|
|
|
bind(index, &val);
|
|
|
|
|
}
|
|
|
|
|
inline virtual void bind(int index, int16_t *val)
|
|
|
|
|
{
|
|
|
|
|
_ASSERT(index < m_count);
|
|
|
|
|
m_params_ptr[index].buffer = val;
|
|
|
|
|
m_params_ptr[index].buffer_type = MYSQL_TYPE_SHORT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline virtual void bind(int index, uint16_t &val)
|
|
|
|
|
{
|
|
|
|
|
bind(index, &val);
|
|
|
|
|
}
|
|
|
|
|
inline virtual void bind(int index, uint16_t *val)
|
|
|
|
|
{
|
|
|
|
|
_ASSERT(index < m_count);
|
|
|
|
|
m_params_ptr[index].buffer = val;
|
|
|
|
|
m_params_ptr[index].buffer_type = MYSQL_TYPE_SHORT;
|
|
|
|
|
m_params_ptr[index].is_unsigned = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// int
|
2018-12-14 16:34:18 -06:00
|
|
|
inline virtual void bind(int index, int32_t &val)
|
|
|
|
|
{
|
|
|
|
|
bind(index, &val);
|
|
|
|
|
}
|
|
|
|
|
inline virtual void bind(int index, int32_t *val)
|
|
|
|
|
{
|
|
|
|
|
_ASSERT(index < m_count);
|
|
|
|
|
m_params_ptr[index].buffer = val;
|
|
|
|
|
m_params_ptr[index].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
|
}
|
2020-08-07 10:58:05 -07:00
|
|
|
inline virtual void bind(int index, double &val)
|
|
|
|
|
{
|
|
|
|
|
bind(index, &val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline virtual void bind(int index, double *val)
|
|
|
|
|
{
|
|
|
|
|
_ASSERT(index < m_count);
|
|
|
|
|
m_params_ptr[index].buffer = val;
|
|
|
|
|
m_params_ptr[index].buffer_type = MYSQL_TYPE_DOUBLE;
|
|
|
|
|
}
|
2018-12-14 16:34:18 -06:00
|
|
|
|
|
|
|
|
inline virtual void bind(int index, uint32_t &val)
|
|
|
|
|
{
|
|
|
|
|
bind(index, &val);
|
|
|
|
|
}
|
|
|
|
|
inline virtual void bind(int index, uint32_t *val)
|
|
|
|
|
{
|
|
|
|
|
_ASSERT(index < m_count);
|
|
|
|
|
m_params_ptr[index].buffer = val;
|
|
|
|
|
m_params_ptr[index].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
|
m_params_ptr[index].is_unsigned = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-08 12:25:04 -06:00
|
|
|
inline virtual void bind(int index, long &val)
|
|
|
|
|
{
|
|
|
|
|
bind(index, &val);
|
|
|
|
|
}
|
|
|
|
|
inline virtual void bind(int index, long *val)
|
|
|
|
|
{
|
|
|
|
|
_ASSERT(index < m_count);
|
|
|
|
|
m_params_ptr[index].buffer = val;
|
|
|
|
|
m_params_ptr[index].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline virtual void bind(int index, unsigned long &val)
|
|
|
|
|
{
|
|
|
|
|
bind(index, &val);
|
|
|
|
|
}
|
|
|
|
|
inline virtual void bind(int index, unsigned long *val)
|
|
|
|
|
{
|
|
|
|
|
_ASSERT(index < m_count);
|
|
|
|
|
m_params_ptr[index].buffer = val;
|
|
|
|
|
m_params_ptr[index].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
|
m_params_ptr[index].is_unsigned = true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-14 16:34:18 -06:00
|
|
|
inline virtual void bind(int index, void *val, size_t length, unsigned long *result_length = nullptr)
|
|
|
|
|
{
|
|
|
|
|
_ASSERT(index < m_count);
|
|
|
|
|
m_params_ptr[index].buffer = val;
|
2019-02-26 22:24:48 +00:00
|
|
|
m_params_ptr[index].buffer_length = (unsigned long)length;
|
2018-12-14 16:34:18 -06:00
|
|
|
m_params_ptr[index].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
|
if (result_length)
|
|
|
|
|
m_params_ptr[index].length = result_length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline virtual void bind(int index, std::string &val)
|
|
|
|
|
{
|
|
|
|
|
bind(index, val, val.length());
|
|
|
|
|
}
|
2018-12-28 18:00:10 -06:00
|
|
|
inline virtual void bind(int index, std::string *val)
|
|
|
|
|
{
|
|
|
|
|
bind(index, val, val->length());
|
|
|
|
|
}
|
2018-12-14 16:34:18 -06:00
|
|
|
inline virtual void bind(int index, std::string &val, size_t length, unsigned long *result_length = nullptr)
|
|
|
|
|
{
|
|
|
|
|
_ASSERT(index < m_count);
|
|
|
|
|
if (val.capacity() < length)
|
|
|
|
|
val.reserve(length);
|
|
|
|
|
|
|
|
|
|
m_params_ptr[index].buffer = val.data();
|
2019-02-26 22:24:48 +00:00
|
|
|
m_params_ptr[index].buffer_length = (unsigned long)length;
|
2018-12-14 16:34:18 -06:00
|
|
|
m_params_ptr[index].buffer_type = MYSQL_TYPE_VAR_STRING;
|
|
|
|
|
if (result_length)
|
|
|
|
|
m_params_ptr[index].length = result_length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline virtual void bind(int index, char *val)
|
|
|
|
|
{
|
|
|
|
|
bind(index, val, strlen(val));
|
|
|
|
|
}
|
|
|
|
|
inline virtual void bind(int index, const char *val)
|
|
|
|
|
{
|
|
|
|
|
bind(index, const_cast<char*>(val), strlen(val));
|
|
|
|
|
}
|
|
|
|
|
inline virtual void bind(int index, char *val, size_t length, unsigned long *result_length = nullptr)
|
|
|
|
|
{
|
|
|
|
|
_ASSERT(index < m_count);
|
|
|
|
|
m_params_ptr[index].buffer = val;
|
2019-02-26 22:24:48 +00:00
|
|
|
m_params_ptr[index].buffer_length = (unsigned long)length;
|
2018-12-14 16:34:18 -06:00
|
|
|
m_params_ptr[index].buffer_type = MYSQL_TYPE_VAR_STRING;
|
|
|
|
|
if (result_length)
|
|
|
|
|
m_params_ptr[index].length = result_length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
2019-01-08 12:25:04 -06:00
|
|
|
inline void bindarg(int index, T& arg) { bind(index, arg); }
|
2018-12-14 16:34:18 -06:00
|
|
|
|
|
|
|
|
template<typename T>
|
2019-01-08 12:25:04 -06:00
|
|
|
inline void bindargs(T& arg) { bindarg(m_count - 1, arg); }
|
2018-12-14 16:34:18 -06:00
|
|
|
|
|
|
|
|
template<typename T, typename ...Args>
|
2019-01-08 12:25:04 -06:00
|
|
|
inline void bindargs(T arg, Args&... args)
|
2018-12-14 16:34:18 -06:00
|
|
|
{
|
2019-01-08 12:25:04 -06:00
|
|
|
bindarg(m_count - (sizeof...(args) + 1), arg);
|
2018-12-14 16:34:18 -06:00
|
|
|
bindargs(args...);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// statement parameters
|
|
|
|
|
|
|
|
|
|
template<int _Count>
|
|
|
|
|
class mysql_statement_params :
|
|
|
|
|
public mysql_param_list_base
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
mysql_statement_params() :
|
|
|
|
|
mysql_param_list_base(m_params, _Count),
|
2019-07-07 20:56:15 +00:00
|
|
|
m_params{ { 0 } }
|
2018-12-14 16:34:18 -06:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
operator MYSQL_BIND*() { return m_params; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
MYSQL_BIND m_params[_Count];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// statement results
|
|
|
|
|
|
|
|
|
|
template<int _Count>
|
|
|
|
|
class mysql_statement_results :
|
|
|
|
|
public mysql_param_list_base
|
|
|
|
|
{
|
|
|
|
|
friend class mysql_statement_base;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
mysql_statement_results() :
|
|
|
|
|
mysql_param_list_base(m_cols, _Count),
|
2019-07-07 20:56:15 +00:00
|
|
|
m_cols{ { 0 } }
|
2018-12-14 16:34:18 -06:00
|
|
|
{
|
|
|
|
|
for (int i = 0; i < _Count; i++)
|
|
|
|
|
{
|
|
|
|
|
m_cols[i].is_null = &m_cols[i].is_null_value;
|
|
|
|
|
m_cols[i].length = &m_cols[i].length_value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isNull(int index)
|
|
|
|
|
{
|
|
|
|
|
_ASSERT(index < _Count);
|
|
|
|
|
return m_cols[index].is_null_value == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t length(int index)
|
|
|
|
|
{
|
|
|
|
|
_ASSERT(index < _Count);
|
|
|
|
|
return m_cols[index].length_value;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-14 17:44:20 -06:00
|
|
|
bool next()
|
|
|
|
|
{
|
|
|
|
|
int res = mysql_stmt_fetch(m_statement);
|
|
|
|
|
return res == 0;
|
|
|
|
|
}
|
2018-12-14 16:34:18 -06:00
|
|
|
|
|
|
|
|
operator MYSQL_BIND*() { return m_cols; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
MYSQL_BIND m_cols[_Count];
|
|
|
|
|
MYSQL_STMT *m_statement;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// statement base for friending results
|
|
|
|
|
|
|
|
|
|
class mysql_statement_base
|
|
|
|
|
{
|
|
|
|
|
protected:
|
2020-06-06 23:22:18 +00:00
|
|
|
mysql_statement_base(MYSQL *dbc) : m_dbc(dbc), m_statement(dbc ? mysql_stmt_init(dbc) : nullptr), m_buffered(false)
|
2018-12-14 16:34:18 -06:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
public:
|
2018-12-14 17:44:20 -06:00
|
|
|
mysql_statement_base(mysql_statement_base&&) = default;
|
|
|
|
|
mysql_statement_base& operator=(mysql_statement_base&&) = default;
|
|
|
|
|
|
2019-01-08 00:37:34 -06:00
|
|
|
virtual ~mysql_statement_base() noexcept
|
|
|
|
|
{
|
2019-01-08 12:25:04 -06:00
|
|
|
if (m_statement && m_buffered)
|
2019-01-08 00:37:34 -06:00
|
|
|
mysql_stmt_free_result(m_statement.get());
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-14 16:34:18 -06:00
|
|
|
inline operator bool() { return (bool)m_statement; }
|
|
|
|
|
inline bool valid() { return (bool)m_statement; }
|
|
|
|
|
|
|
|
|
|
template<int _ColCount>
|
|
|
|
|
bool bindResults(mysql_statement_results<_ColCount> &results)
|
|
|
|
|
{
|
|
|
|
|
if (mysql_stmt_bind_result(m_statement.get(), results))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
results.m_statement = m_statement.get();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-27 15:47:25 -06:00
|
|
|
inline std::string error() const { return mysql_error(m_dbc); }
|
|
|
|
|
|
2019-01-08 00:37:34 -06:00
|
|
|
virtual inline bool execute() { return execute(true); }
|
|
|
|
|
|
|
|
|
|
virtual bool execute(bool buffer)
|
|
|
|
|
{
|
|
|
|
|
if (mysql_stmt_execute(m_statement.get()))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (buffer)
|
|
|
|
|
{
|
|
|
|
|
if (mysql_stmt_store_result(m_statement.get()))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
m_buffered = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-06 23:22:18 +00:00
|
|
|
virtual uint64_t lastInsertId()
|
|
|
|
|
{
|
|
|
|
|
return mysql_insert_id(m_dbc);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-14 16:34:18 -06:00
|
|
|
protected:
|
2018-12-27 15:47:25 -06:00
|
|
|
MYSQL *m_dbc;
|
2018-12-14 16:34:18 -06:00
|
|
|
mysql_stmt_ptr_t m_statement;
|
2019-01-08 00:37:34 -06:00
|
|
|
bool m_buffered;
|
|
|
|
|
|
2018-12-14 16:34:18 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// statement
|
|
|
|
|
|
|
|
|
|
template<int _Count>
|
|
|
|
|
class mysql_statement :
|
|
|
|
|
public mysql_statement_base,
|
|
|
|
|
public mysql_param_list_base
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
mysql_statement(MYSQL *dbc, std::string query) :
|
|
|
|
|
mysql_statement_base(dbc),
|
|
|
|
|
mysql_param_list_base(m_params, _Count),
|
|
|
|
|
m_query(query), m_params()
|
|
|
|
|
{
|
|
|
|
|
if (valid())
|
|
|
|
|
if (mysql_stmt_prepare(m_statement.get(), m_query.c_str(), m_query.length()))
|
|
|
|
|
m_statement.reset(nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-14 17:44:20 -06:00
|
|
|
mysql_statement(mysql_statement&&) = default;
|
|
|
|
|
mysql_statement& operator=(mysql_statement&&) = default;
|
|
|
|
|
|
2019-01-08 00:37:34 -06:00
|
|
|
virtual ~mysql_statement() noexcept override = default;
|
|
|
|
|
|
2019-01-08 12:25:04 -06:00
|
|
|
virtual bool execute() override { return mysql_statement_base::execute(); }
|
2019-01-08 00:37:34 -06:00
|
|
|
|
|
|
|
|
virtual bool execute(bool buffer) override
|
2018-12-14 16:34:18 -06:00
|
|
|
{
|
|
|
|
|
if (mysql_stmt_bind_param(m_statement.get(), m_params))
|
|
|
|
|
return false;
|
|
|
|
|
|
2019-01-08 00:37:34 -06:00
|
|
|
return mysql_statement_base::execute(buffer);
|
2018-12-14 16:34:18 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
std::string m_query;
|
|
|
|
|
mysql_statement_params<_Count> m_params;
|
2019-01-08 00:37:34 -06:00
|
|
|
|
2018-12-14 16:34:18 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// statement specialization for zero parameters
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
class mysql_statement<0> :
|
|
|
|
|
public mysql_statement_base,
|
|
|
|
|
public mysql_param_list_base
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
mysql_statement(MYSQL *dbc, std::string query) :
|
|
|
|
|
mysql_statement_base(dbc),
|
|
|
|
|
mysql_param_list_base(nullptr, 0),
|
|
|
|
|
m_query(query)
|
|
|
|
|
{
|
|
|
|
|
if (valid())
|
2019-02-26 22:24:48 +00:00
|
|
|
if (mysql_stmt_prepare(m_statement.get(), m_query.c_str(), (unsigned long)m_query.length()))
|
2018-12-14 16:34:18 -06:00
|
|
|
m_statement.reset(nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-08 12:25:04 -06:00
|
|
|
virtual bool execute() override { return mysql_statement_base::execute(); }
|
2018-12-14 16:34:18 -06:00
|
|
|
|
2019-01-08 00:37:34 -06:00
|
|
|
virtual bool execute(bool buffer) override
|
|
|
|
|
{
|
|
|
|
|
return mysql_statement_base::execute(buffer);
|
2018-12-14 16:34:18 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
std::string m_query;
|
2019-07-07 20:56:15 +00:00
|
|
|
};
|