C++ 封装C语言MYSQL PrepareStatement 接口(mysql

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

例子

	auto stmt = pMysqlSession->findByIndex(StmtGMArenaSeasonPlayer::ID);
	auto pStmtData = static_cast<StmtGMArenaSeasonPlayer*>(stmt->getStmtData());

	pStmtData->bindParams(fb->player_id(), fb->season_id());
	stmt->exec();

	int maxRank = 0;
	int count = 0;
	if (stmt->fetch())
	{
		maxRank = pStmtData->get_max_rank();
		count = pStmtData->get_count();
	}

源文件

StmtGMArenaCount::StmtGMArenaCount()
	: MysqlStmtData(ID, MYSQL_STMT_TYPE::PROCESS, "CALL cmd_arena_count(?,?,?,?,?);")
{
	clear();
}

void StmtGMArenaCount::bind(MysqlPrepareStmt* pStmt)
{
	pStmt->bind(DatabaseStmtBindArgs(DATABASE_STMT_BIND_TYPE_PARAM, DATABASE_STMT_TYPE::INT, 0, "params.m_begin_time", &params.m_begin_time, nullptr));
	pStmt->bind(DatabaseStmtBindArgs(DATABASE_STMT_BIND_TYPE_PARAM, DATABASE_STMT_TYPE::INT, 1, "params.m_end_time", &params.m_end_time, nullptr));
	pStmt->bind(DatabaseStmtBindArgs(DATABASE_STMT_BIND_TYPE_PARAM, DATABASE_STMT_TYPE::BYTE, 2, "params.m_including_ai", &params.m_including_ai, nullptr));
	pStmt->bind(DatabaseStmtBindArgs(DATABASE_STMT_BIND_TYPE_PARAM, DATABASE_STMT_TYPE::BYTE, 3, "params.m_including_giveup", &params.m_including_giveup, nullptr));
	pStmt->bind(DatabaseStmtBindArgs(DATABASE_STMT_BIND_TYPE_PARAM, DATABASE_STMT_TYPE::INT, 4, "params.m_inopt", &params.m_inopt, nullptr));
	pStmt->bind(DatabaseStmtBindArgs(DATABASE_STMT_BIND_TYPE_RESULT, DATABASE_STMT_TYPE::INT, 0, "results.m_count", &results.m_count, nullptr));
}

void StmtGMArenaCount::clear()
{
	memset(&params, 0, sizeof(params));
	memset(&results, 0, sizeof(results));
}

void StmtGMArenaCount::bindParams(int32_t inopt, int32_t begin_time, int32_t end_time, int8_t including_ai, int8_t including_giveup)
{
	set_inopt(inopt);
	set_begin_time(begin_time);
	set_end_time(end_time);
	set_including_ai(including_ai);
	set_including_giveup(including_giveup);
}

void StmtGMArenaCount::set_begin_time(int32_t begin_time)
{
	params.m_begin_time = begin_time;
}

void StmtGMArenaCount::set_end_time(int32_t end_time)
{
	params.m_end_time = end_time;
}

void StmtGMArenaCount::set_inopt(int32_t inopt)
{
	params.m_inopt = inopt;
}

void StmtGMArenaCount::set_including_ai(int8_t including_ai)
{
	params.m_including_ai = including_ai;
}

void StmtGMArenaCount::set_including_giveup(int8_t including_giveup)
{
	params.m_including_giveup = including_giveup;
}

int32_t StmtGMArenaCount::get_count() const
{
	return results.m_count;
}

头文件 

struct StmtGMArenaCount final: public MysqlStmtData
{
	StmtGMArenaCount();
	virtual ~StmtGMArenaCount() = default;
	enum { ID = 40 };
	virtual uint32_t getParamCount() override { return 5; }
	virtual uint32_t getResultCount() override { return 1; }
	virtual void bind(MysqlPrepareStmt* pStmt) override;
	void clear();
	void bindParams(int32_t inopt, int32_t begin_time, int32_t end_time, int8_t including_ai, int8_t including_giveup);
	void set_inopt(int32_t inopt);
	void set_begin_time(int32_t begin_time);
	void set_end_time(int32_t end_time);
	void set_including_ai(int8_t including_ai);
	void set_including_giveup(int8_t including_giveup);
	int32_t get_count() const;

	struct Params
	{
		int32_t m_begin_time;
		int32_t m_end_time;
		int8_t m_including_ai;
		int8_t m_including_giveup;
		int32_t m_inopt;
	} params;

	struct Results
	{
		int32_t m_count;
	} results;
};

MysqlStmtData.h

#pragma once

#include "prerequisites.h"


enum class MYSQL_STMT_TYPE
{
	UPDATE,								// insert delete update replace 无返回的存储过程
	SELECT,								// select
	PROCESS,							// 有返回的存储过程
};

class MysqlPrepareStmt;

// 预处理数据
class MysqlStmtData : private boost::noncopyable
{
public:
	MysqlStmtData(uint32_t index, MYSQL_STMT_TYPE type, const char* sql);

	virtual ~MysqlStmtData() = default;

	virtual uint32_t getParamCount() = 0;

	virtual uint32_t getResultCount() = 0;

	virtual	void bind(MysqlPrepareStmt* pStmt) = 0;


	uint32_t getIndex() const;
	MYSQL_STMT_TYPE getType() const;
	const char* getSql() const;

protected:
	unsigned long bindString(char* szDest, size_t nDestCount, std::string_view src);

protected:
	uint32_t								m_index;
	MYSQL_STMT_TYPE							m_type;
	const char* m_sql;
};


inline uint32_t MysqlStmtData::getIndex() const
{
	return m_index;
}

inline MYSQL_STMT_TYPE MysqlStmtData::getType() const
{
	return m_type;
}

inline const char* MysqlStmtData::getSql() const
{
	return m_sql;
}

MysqlStmtData.cpp

#include "MysqlStmtData.h"

MysqlStmtData::MysqlStmtData(uint32_t index, MYSQL_STMT_TYPE type, const char* sql)
	: m_index(index)
	, m_type(type)
	, m_sql(sql)
{
}

unsigned long MysqlStmtData::bindString(char* szDest, size_t nDestCount, std::string_view src)
{
	if (src.empty())
	{
		szDest[0] = 0;
		return 0;
	}

	unsigned long len = std::min<unsigned long>(nDestCount, src.size());
	memcpy(szDest, src.data(), len);
	return len;
}

MysqlPrepareStmt.cpp


#include "MysqlPrepareStmt.h"
#include "MysqlException.h"


MysqlPrepareStmt::MysqlPrepareStmt()
	: m_stmt(nullptr)
	, m_pStmtData(nullptr)
{
	memset(m_pBind, 0, sizeof(m_pBind));
	memset(m_bindSize, 0, sizeof(m_bindSize));
}

MysqlPrepareStmt::~MysqlPrepareStmt()
{
	close();

	for (int i = 0; i < DATABASE_STMT_BIND_TYPE_MAX; i++)
	{
		if (m_pBind[i])
		{
			delete[] m_pBind[i];
			m_pBind[i] = nullptr;
		}
		m_bindSize[i] = 0;
	}
}

void MysqlPrepareStmt::load(MysqlStmtData* pStmtData)
{
	uint32_t size = pStmtData->getParamCount();
	if (size > 0)
	{
		m_pBind[DATABASE_STMT_BIND_TYPE_PARAM] = DEBUG_NEW MYSQL_BIND[size];
		memset(m_pBind[DATABASE_STMT_BIND_TYPE_PARAM], 0, sizeof(MYSQL_BIND) * size);
		m_bindSize[DATABASE_STMT_BIND_TYPE_PARAM] = size;
	}

	size = pStmtData->getResultCount();
	if (size > 0)
	{
		m_pBind[DATABASE_STMT_BIND_TYPE_RESULT] = DEBUG_NEW MYSQL_BIND[size];
		memset(m_pBind[DATABASE_STMT_BIND_TYPE_RESULT], 0, sizeof(MYSQL_BIND) * size);
		m_bindSize[DATABASE_STMT_BIND_TYPE_RESULT] = size;
	}

	pStmtData->bind(this);

	m_pStmtData = pStmtData;
}

void MysqlPrepareStmt::initialize(MYSQL* pMysql)
{
	if (!m_pStmtData)
	{
		MYSQL_DB_THROW("m_pStmtData == nullptr");
	}

	close();

	const char* sql = m_pStmtData->getSql();
	if (!(sql && sql[0]))
	{
		MYSQL_DB_THROW(fmt::format("sql is empty,index={}", m_pStmtData->getIndex()));
	}

	m_stmt = mysql_stmt_init(pMysql);
	if (!m_stmt)
	{
		MYSQL_DB_THROW(mysql_errno(pMysql), mysql_error(pMysql), mysql_sqlstate(pMysql), fmt::format("mysql_stmt_init fail,index={},sql={}", m_pStmtData->getIndex(), sql));
	}

	if (mysql_stmt_prepare(m_stmt, sql, (unsigned long)strlen(sql)))
	{
		uint32_t uerrno = mysql_errno(pMysql);
		std::string strerror = mysql_error(pMysql);
		std::string strstate = mysql_sqlstate(pMysql);

		mysql_stmt_close(m_stmt);
		m_stmt = nullptr;

		MYSQL_DB_THROW(uerrno, strerror.c_str(), strstate.c_str(), fmt::format("mysql_stmt_prepare fail,index={},sql={}", m_pStmtData->getIndex(), sql));
	}

	bindComplete();
}

void MysqlPrepareStmt::close()
{
	if (m_stmt)
	{
		mysql_stmt_close(m_stmt);
		m_stmt = nullptr;
	}
}

void MysqlPrepareStmt::bindComplete()
{
	bindParam();

	if (m_pStmtData->getType() == MYSQL_STMT_TYPE::SELECT)
	{
		bindResult();
	}
}

void MysqlPrepareStmt::bindParam()
{
	if (0 != mysql_stmt_bind_param(m_stmt, m_pBind[DATABASE_STMT_BIND_TYPE_PARAM]))
	{
		MYSQL_DB_THROW(mysql_stmt_errno(m_stmt), mysql_stmt_error(m_stmt), mysql_stmt_sqlstate(m_stmt), fmt::format("mysql_stmt_bind_param fail,index={},sql={}", m_pStmtData->getIndex(), m_pStmtData->getSql()));
	}

	unsigned long size = mysql_stmt_param_count(m_stmt);
	if (size != m_bindSize[DATABASE_STMT_BIND_TYPE_PARAM])
	{
		MYSQL_DB_THROW(fmt::format("index={},sql={}, bind param size({}) != max({})", m_pStmtData->getIndex(), m_pStmtData->getSql(), size, m_bindSize[DATABASE_STMT_BIND_TYPE_PARAM]));
	}
}

void MysqlPrepareStmt::bindResult()
{
	if (0 != mysql_stmt_bind_result(m_stmt, m_pBind[DATABASE_STMT_BIND_TYPE_RESULT]))
	{
		MYSQL_DB_THROW(mysql_stmt_errno(m_stmt), mysql_stmt_error(m_stmt), mysql_stmt_sqlstate(m_stmt), fmt::format("mysql_stmt_bind_result fail,index={}", m_pStmtData->getIndex()));
	}
}

int MysqlPrepareStmt::exec()
{
	if (0 != mysql_stmt_execute(m_stmt))
	{
		MYSQL_DB_THROW(mysql_stmt_errno(m_stmt), mysql_stmt_error(m_stmt), mysql_stmt_sqlstate(m_stmt), fmt::format("mysql_stmt_execute fail,index={}", m_pStmtData->getIndex()));
	}

	if (m_pStmtData->getType() == MYSQL_STMT_TYPE::UPDATE)
	{
		return (int)mysql_stmt_affected_rows(m_stmt);
	}

	if (0 != mysql_stmt_store_result(m_stmt))
	{
		MYSQL_DB_THROW(mysql_stmt_errno(m_stmt), mysql_stmt_error(m_stmt), mysql_stmt_sqlstate(m_stmt), fmt::format("mysql_stmt_store_result fail,index={}", m_pStmtData->getIndex()));
	}

	if (m_pStmtData->getType() == MYSQL_STMT_TYPE::PROCESS)
	{
		bindResult();
	}

	return 0;
}

bool MysqlPrepareStmt::fetch()
{
	int ret = mysql_stmt_fetch(m_stmt);
	if (1 == ret)
	{
		MYSQL_DB_THROW(mysql_stmt_errno(m_stmt), mysql_stmt_error(m_stmt), mysql_stmt_sqlstate(m_stmt), fmt::format("mysql_stmt_fetch fail,index={}", m_pStmtData->getIndex()));
	}

	return MYSQL_NO_DATA != ret;
}

void MysqlPrepareStmt::clear()
{
	if (m_pStmtData->getType() == MYSQL_STMT_TYPE::UPDATE)
	{
		return;
	}

	//取没有取完的
	while (0 == mysql_stmt_fetch(m_stmt));

	if (m_pStmtData->getType() == MYSQL_STMT_TYPE::SELECT)
	{
		return;
	}

	do
	{
		MYSQL_RES* result = mysql_store_result(m_stmt->mysql);
		mysql_free_result(result);
	} while (!mysql_next_result(m_stmt->mysql));
}

uint64_t MysqlPrepareStmt::getInsertId()
{
	return (uint64_t)mysql_stmt_insert_id(m_stmt);
}

uint64_t MysqlPrepareStmt::getAffectedRows()
{
	return (uint64_t)mysql_stmt_affected_rows(m_stmt);
}

void MysqlPrepareStmt::bind(const DatabaseStmtBindArgs& args)
{
	switch (args.bindType)
	{
	case DATABASE_STMT_BIND_TYPE_PARAM:
	case DATABASE_STMT_BIND_TYPE_RESULT:
		break;
	default:
		MYSQL_DB_THROW(fmt::format("index={},sql={}, args bindType error: {}", m_pStmtData->getIndex(), m_pStmtData->getSql(), (int)args.bindType));
		break;
	}

	if (args.index >= m_bindSize[args.bindType])
	{
		MYSQL_DB_THROW(fmt::format("index={},sql={}, args idx({}:{}) >= max({})", m_pStmtData->getIndex(), m_pStmtData->getSql(), args.index, (args.indexName ? args.indexName : "NULL"), m_bindSize[args.bindType]));
	}

	if (nullptr == args.buffer)
	{
		MYSQL_DB_THROW(fmt::format("index={},sql={}, args buffer is null", m_pStmtData->getIndex(), m_pStmtData->getSql()));
	}

	if (DATABASE_STMT_TYPE::STRING == args.type ||
		DATABASE_STMT_TYPE::VARSTRING == args.type ||
		DATABASE_STMT_TYPE::TINYBLOB == args.type ||
		DATABASE_STMT_TYPE::BLOB == args.type ||
		DATABASE_STMT_TYPE::MEDIUMBLOB == args.type)
	{
		if (0 == args.bufferSize || nullptr == args.bufferUsed)
		{
			MYSQL_DB_THROW(fmt::format("index={},sql={}, args buffer size is 0", m_pStmtData->getIndex(), m_pStmtData->getSql()));
		}
	}

	if (nullptr != m_pBind[args.bindType][args.index].buffer)
	{
		MYSQL_DB_THROW(fmt::format("index={},sql={}, bind args is exist, type={}, idx={}:{}", m_pStmtData->getIndex(), m_pStmtData->getSql(), (int)args.bindType, args.index, (args.indexName ? args.indexName : "NULL")));
	}

	switch (args.type)
	{
	case DATABASE_STMT_TYPE::BOOL:
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_TINY;
		m_pBind[args.bindType][args.index].is_unsigned = true;
		break;
	case DATABASE_STMT_TYPE::BYTE:
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_TINY;
		m_pBind[args.bindType][args.index].is_unsigned = false;
		break;
	case DATABASE_STMT_TYPE::UBYTE:
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_TINY;
		m_pBind[args.bindType][args.index].is_unsigned = true;
		break;
	case DATABASE_STMT_TYPE::SHORT:
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_SHORT;
		m_pBind[args.bindType][args.index].is_unsigned = false;
		break;
	case DATABASE_STMT_TYPE::USHORT:
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_SHORT;
		m_pBind[args.bindType][args.index].is_unsigned = true;
		break;
	case DATABASE_STMT_TYPE::INT:
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_LONG;
		m_pBind[args.bindType][args.index].is_unsigned = false;
		break;
	case DATABASE_STMT_TYPE::UINT:
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_LONG;
		m_pBind[args.bindType][args.index].is_unsigned = true;
		break;
	case DATABASE_STMT_TYPE::LONG:
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_LONGLONG;
		m_pBind[args.bindType][args.index].is_unsigned = false;
		break;
	case DATABASE_STMT_TYPE::ULONG:
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_LONGLONG;
		m_pBind[args.bindType][args.index].is_unsigned = true;
		break;
	case DATABASE_STMT_TYPE::FLOAT:
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_FLOAT;
		break;
	case DATABASE_STMT_TYPE::DOUBLE:
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_DOUBLE;
		break;
	case DATABASE_STMT_TYPE::STRING:
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_STRING;
		break;
	case DATABASE_STMT_TYPE::VARSTRING:
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_VAR_STRING;
		break;
	case DATABASE_STMT_TYPE::TINYBLOB:
		// 255 byte
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_TINY_BLOB;
		break;
	case DATABASE_STMT_TYPE::BLOB:
		// (2^16-1) byte
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_BLOB;
		break;
	case DATABASE_STMT_TYPE::MEDIUMBLOB:
		// (2^24-1) byte
		m_pBind[args.bindType][args.index].buffer_type = MYSQL_TYPE_MEDIUM_BLOB;
		break;
	default:
		MYSQL_DB_THROW(fmt::format("index={},sql={}, args type error", m_pStmtData->getIndex(), m_pStmtData->getSql()));
		break;
	}

	m_pBind[args.bindType][args.index].buffer = args.buffer;

	if (DATABASE_STMT_TYPE::STRING == args.type ||
		DATABASE_STMT_TYPE::VARSTRING == args.type ||
		DATABASE_STMT_TYPE::TINYBLOB == args.type ||
		DATABASE_STMT_TYPE::BLOB == args.type ||
		DATABASE_STMT_TYPE::MEDIUMBLOB == args.type)
	{

		m_pBind[args.bindType][args.index].buffer_length = args.bufferSize;
		m_pBind[args.bindType][args.index].length = args.bufferUsed;
		*args.bufferUsed = 0;
	}

	if (args.maybeNull)
	{
		m_pBind[args.bindType][args.index].is_null = args.maybeNull;
		*args.maybeNull = 0;
	}
}

MysqlPrepareStmt.h

#pragma once

#include "prerequisites.h"
#include <mysql.h>
#include <errmsg.h>
#include <mysqld_error.h>
#include "MysqlStmtData.h"


enum DATABASE_STMT_BIND_TYPE
{
	DATABASE_STMT_BIND_TYPE_PARAM,				// 绑定参数
	DATABASE_STMT_BIND_TYPE_RESULT,				// 绑定结果
	DATABASE_STMT_BIND_TYPE_MAX,
};

enum class DATABASE_STMT_TYPE
{
	BOOL,
	BYTE,
	UBYTE,
	SHORT,
	USHORT,
	INT,
	UINT,
	LONG,
	ULONG,
	FLOAT,
	DOUBLE,
	STRING,
	VARSTRING,
	TINYBLOB,
	BLOB,
	MEDIUMBLOB,
};

struct DatabaseStmtBindArgs
{
	DatabaseStmtBindArgs(DATABASE_STMT_BIND_TYPE bindType_
		, DATABASE_STMT_TYPE type_
		, uint32_t index_
		, const char* indexName_
		, void* buffer_
		, my_bool* maybeNull_)
		: bindType(bindType_)
		, type(type_)
		, index(index_)
		, indexName(indexName_)
		, buffer(buffer_)
		, bufferSize(0)
		, bufferUsed(nullptr)
		, maybeNull(maybeNull_)
	{
	}

	DatabaseStmtBindArgs(DATABASE_STMT_BIND_TYPE bindType_
		, DATABASE_STMT_TYPE type_
		, uint32_t index_
		, const char* indexName_
		, void* buffer_
		, uint32_t bufferSize_
		, unsigned long* bufferUsed_
		, my_bool* maybeNull_)
		: bindType(bindType_)
		, type(type_)
		, index(index_)
		, indexName(indexName_)
		, buffer(buffer_)
		, bufferSize(bufferSize_)
		, bufferUsed(bufferUsed_)
		, maybeNull(maybeNull_)
	{
	}

	DATABASE_STMT_BIND_TYPE					bindType;
	DATABASE_STMT_TYPE						type;
	uint32_t								index;
	const char* indexName;
	void* buffer;
	uint32_t								bufferSize; // string blob..
	unsigned long* bufferUsed;
	my_bool* maybeNull;
};

// mysql预处理
class MysqlPrepareStmt : private boost::noncopyable
{
public:
	MysqlPrepareStmt();
	virtual ~MysqlPrepareStmt();

	virtual void load(MysqlStmtData* pStmtData);

	virtual MysqlStmtData* getStmtData();

	virtual void initialize(MYSQL* pMysql);

	virtual void close();

	virtual bool isvalid() const;

	virtual void bind(const DatabaseStmtBindArgs& args);

public:
	virtual int exec();

	virtual bool fetch();

	virtual void clear();

	uint64_t getInsertId();

	uint64_t getAffectedRows();

private:
	void bindComplete();

	void bindParam();

	void bindResult();

private:
	MYSQL_STMT* m_stmt;
	MYSQL_BIND* m_pBind[DATABASE_STMT_BIND_TYPE_MAX];
	uint32_t								m_bindSize[DATABASE_STMT_BIND_TYPE_MAX];

	MysqlStmtData* m_pStmtData;
};


inline MysqlStmtData* MysqlPrepareStmt::getStmtData()
{
	return m_pStmtData;
}

inline bool MysqlPrepareStmt::isvalid() const
{
	return nullptr != m_stmt && nullptr != m_pStmtData;
}

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: mysqlc++