SQLITE3 KG-CC

KG-FCL(GAME)

Sqlite3Database.h

cpp 复制代码
#pragma once

#include <iostream>
#include <atomic>
#include <iomanip>
#include <functional>

#include "sqlite3/sqlite3.h"

class Sqlite3Database {
	struct PreparedStatement {
		~PreparedStatement() noexcept;

		sqlite3_stmt*					p = NULL;
	};

public:
	virtual ~Sqlite3Database() noexcept;
	bool								Open(const char* szDatabaseFilePath) noexcept;
	bool								IsAvailable() noexcept { return NULL != pDB_; }
	std::string							GetDatabaseFilePath() noexcept { return pDatabaseFilePath_; }

	int									GetAffectedRows() noexcept;

public:
	int									ExecuteNonQuery(const char* szSQL, const char** szParams, int nParamCount) noexcept;

	template <typename StringIterator>
	int									ExecuteNonQuery(const char* szSQL, const StringIterator& itParamTail, const StringIterator& itParamEndl) noexcept;

public:
	using								RowHandler = std::function<bool(Sqlite3Database*, sqlite3_stmt*)>;

	template <typename StringIterator>
	int									ExecuteQuery(const char* szSQL, const StringIterator& itParamTail, const StringIterator& itParamEndl, const RowHandler& rows) noexcept;

private:
	bool								Finalize(sqlite3* pDB) noexcept;
	int									Internal_ExecuteQuery(const char* szSQL, void* pState, bool cbFillParams(Sqlite3Database*, sqlite3_stmt*, void*), bool (*cbRow)(Sqlite3Database*, sqlite3_stmt*, void*)) noexcept;
	int									Internal_ExecuteNonQuery(const char* szSQL, void* pState, bool cbFillParams(Sqlite3Database*, sqlite3_stmt*, void*)) noexcept;

	template <typename StringIterator>  
	bool								Internal_FillQueryParameters(sqlite3_stmt* pStmt, const StringIterator& itTail, const StringIterator& itEndl) noexcept;

	// C++ 11/14(c++0x/1y)
	template <typename T>
	typename std::enable_if<std::is_pointer<typename std::decay<T>::type>::value, bool>::type
	Internal_FillQueryParameters_Bind_Text(sqlite3_stmt* pStmt, int index, T&& param)
	{
		const char* szParam = param ? param : "";
		return sqlite3_bind_text(pStmt, index, szParam, -1, SQLITE_STATIC) == SQLITE_OK;
	}

	template <typename T>
	typename std::enable_if<!std::is_pointer<typename std::decay<T>::type>::value, bool>::type
	Internal_FillQueryParameters_Bind_Text(sqlite3_stmt* pStmt, int index, T&& param)
	{
		return sqlite3_bind_text(pStmt, index, param.data(), param.size(), SQLITE_STATIC) == SQLITE_OK;
	}

private:
	std::atomic<sqlite3*>				pDB_ = NULL;
	std::string							pDatabaseFilePath_;
};

template <typename StringIterator>
bool Sqlite3Database::Internal_FillQueryParameters(sqlite3_stmt* pStmt, const StringIterator& itTail, const StringIterator& itEndl) noexcept
{
	if (itTail == itEndl) {
		return true;
	}

	int iParamIndex = 1;
	for (auto it = itTail; it != itEndl; ++it) {
		using TString = typename std::remove_reference<typename std::remove_const<decltype(*it)>::type>::type;

		TString szParam = std::move(*it);
		Internal_FillQueryParameters_Bind_Text(pStmt, iParamIndex++, szParam); // non-c++17(1z) not using constexpr.
	}

	return true;
}

template <typename StringIterator>
inline
int Sqlite3Database::ExecuteNonQuery(const char* szSQL, const StringIterator& itParamTail, const StringIterator& itParamEndl) noexcept {
	if (NULL == szSQL || *szSQL == '\x0') {
		return -1;
	}

	struct ExecuteNonQueryContext {
		StringIterator itTail;
		StringIterator itEndl;
	} stExecuteNonQueryContext{ itParamTail, itParamEndl };

	return Internal_ExecuteNonQuery(szSQL, &stExecuteNonQueryContext,
		[](Sqlite3Database* pDB, sqlite3_stmt* pStmt, void* p) noexcept -> bool {
			auto* pCtx = static_cast<ExecuteNonQueryContext*>(p);
			return pDB->Internal_FillQueryParameters(pStmt, pCtx->itTail, pCtx->itEndl);
		});
}

template <typename StringIterator>
inline
int Sqlite3Database::ExecuteQuery(const char* szSQL, const StringIterator& itParamTail, const StringIterator& itParamEndl, const RowHandler& rows) noexcept {
	if (NULL == szSQL || *szSQL == '\x0') {
		return -1;
	}

	if (!rows) {
		return -1;
	}

	struct ExecuteQueryContext {
		StringIterator	itTail;
		StringIterator	itEndl;
		RowHandler		fnRows;
	} stExecuteQueryContext{ itParamTail, itParamEndl, rows };

	auto fnFillParams =
		[](Sqlite3Database* pDB, sqlite3_stmt* pStmt, void* p) noexcept -> bool {
			ExecuteQueryContext* pCtx = static_cast<ExecuteQueryContext*>(p);
			return pDB->Internal_FillQueryParameters(pStmt, pCtx->itTail, pCtx->itEndl);
		};

	auto fnRows =
		[](Sqlite3Database* pDB, sqlite3_stmt* pStmt, void* p) noexcept -> bool {
			ExecuteQueryContext* pCtx = static_cast<ExecuteQueryContext*>(p);
			return pCtx->fnRows(pDB, pStmt);
		};
	return Internal_ExecuteQuery(szSQL, &stExecuteQueryContext, fnFillParams, fnRows);
}

Sqlite3Database.cpp

cpp 复制代码
#include "stdafx.h"
#include "Sqlite3Database.h"

#include "sqlite3/sqlite3.h"

//#ifdef _MSC_VER
//#pragma comment(lib, "sqlite3/sqlite3.lib")
//#endif

// 假设 LogOutput 已定义,这里不再重复包含头文件

Sqlite3Database::PreparedStatement::~PreparedStatement() noexcept {
    sqlite3_stmt* stmt = p;
    if (stmt) {
        p = NULL;
        sqlite3_finalize(stmt);
        // 日志:语句被清理
        LogOutput(KGLOG_DEBUG, "PreparedStatement finalized.\n");
    }
}

Sqlite3Database::~Sqlite3Database() noexcept {
    sqlite3* pOld = pDB_.exchange(NULL);
    Finalize(pOld);
    // 日志:数据库对象析构
    LogOutput(KGLOG_DEBUG, "Sqlite3Database destroyed.\n");
}

bool Sqlite3Database::Open(const char* szDatabaseFilePath) noexcept {
    if (NULL == szDatabaseFilePath || *szDatabaseFilePath == '\x0') {
        LogOutput(KGLOG_WARNING, "Open failed: invalid file path.\n");
        return false;
    }

    sqlite3* pDB;
    int rc = sqlite3_open(szDatabaseFilePath, &pDB);
    if (rc) {
        LogOutput(KGLOG_WARNING, "Open failed: sqlite3_open error %d for %s\n", rc, szDatabaseFilePath);
        return false;
    }

    Finalize(pDB_.exchange(pDB));
    pDatabaseFilePath_ = szDatabaseFilePath;
    LogOutput(KGLOG_INFO, "Database opened: %s\n", szDatabaseFilePath);
    return true;
}

bool Sqlite3Database::Finalize(sqlite3* pDB) noexcept {
    if (NULL == pDB) {
        return false;
    }

    if (pDB) {
        sqlite3_close(pDB);
        LogOutput(KGLOG_DEBUG, "Database closed.\n");
        return true;
    }

    return false;
}

int Sqlite3Database::Internal_ExecuteNonQuery(const char* szSQL, void* pState, bool cbFillParams(Sqlite3Database*, sqlite3_stmt*, void*)) noexcept {
    sqlite3* pDB = pDB_;
    if (NULL == pDB) {
        LogOutput(KGLOG_WARNING, "Internal_ExecuteNonQuery: no database connection.\n");
        return -1;
    }

    PreparedStatement stStmt;
    if (sqlite3_prepare_v2(pDB, szSQL, -1, &stStmt.p, NULL) != SQLITE_OK) {
        LogOutput(KGLOG_WARNING, "Internal_ExecuteNonQuery: prepare failed for SQL: %s\n", szSQL ? szSQL : "(null)");
        return -1;
    }

    if (!cbFillParams(this, stStmt.p, pState)) {
        LogOutput(KGLOG_WARNING, "Internal_ExecuteNonQuery: binding parameters failed for SQL: %s\n", szSQL ? szSQL : "(null)");
        return -1;
    }

    if (sqlite3_step(stStmt.p) != SQLITE_DONE) {
        LogOutput(KGLOG_WARNING, "Internal_ExecuteNonQuery: step failed for SQL: %s\n", szSQL ? szSQL : "(null)");
        return -1;
    }

    int nChanges = sqlite3_changes(pDB);
    LogOutput(KGLOG_DEBUG, "Internal_ExecuteNonQuery: executed SQL: %s, rows affected: %d\n", szSQL ? szSQL : "(null)", nChanges);
    return nChanges;
}

int Sqlite3Database::GetAffectedRows() noexcept {
    sqlite3* pDB = pDB_;
    if (NULL == pDB) {
        return -1;
    }

    return sqlite3_changes(pDB);
}

int Sqlite3Database::ExecuteNonQuery(const char* szSQL, const char** szParams, int nParamCount) noexcept {
    if (NULL == szSQL || *szSQL == '\x0') {
        LogOutput(KGLOG_WARNING, "ExecuteNonQuery: empty SQL.\n");
        return -1;
    }

    if (nParamCount < 0 || NULL == szParams && nParamCount != 0) {
        LogOutput(KGLOG_WARNING, "ExecuteNonQuery: invalid parameters (nParamCount=%d, szParams=%p)\n", nParamCount, szParams);
        return -1;
    }

    struct ExecuteNonQueryContext {
        const char** szParams;
        int				nParamCount;
    } stExecuteNonQueryContext;

    stExecuteNonQueryContext.szParams = szParams;
    stExecuteNonQueryContext.nParamCount = nParamCount;

    LogOutput(KGLOG_DEBUG, "ExecuteNonQuery: SQL=%s, paramCount=%d\n", szSQL, nParamCount);
    return Internal_ExecuteNonQuery(szSQL, &stExecuteNonQueryContext,
        [](Sqlite3Database* pDB, sqlite3_stmt* pStmt, void* p) noexcept {
            ExecuteNonQueryContext* pCtx = static_cast<ExecuteNonQueryContext*>(p);
            for (int i = 0; i < pCtx->nParamCount; i++) {
                const char* szParam = pCtx->szParams[i];
                if (!szParam) {
                    szParam = "";
                }

                if (sqlite3_bind_text(pStmt, i + 1, szParam, -1, SQLITE_STATIC) != SQLITE_OK) {
                    LogOutput(KGLOG_WARNING, "ExecuteNonQuery: bind parameter %d failed.\n", i);
                    return false;
                }
            }
            return true;
        });
}

int Sqlite3Database::Internal_ExecuteQuery(const char* szSQL, void* pState, bool cbFillParams(Sqlite3Database*, sqlite3_stmt*, void*), bool (*cbRow)(Sqlite3Database*, sqlite3_stmt*, void*)) noexcept {
    sqlite3* pDB = pDB_;
    if (NULL == pDB) {
        LogOutput(KGLOG_WARNING, "Internal_ExecuteQuery: no database connection.\n");
        return -1;
    }

    PreparedStatement stStmt;
    int rc = sqlite3_prepare_v2(pDB, szSQL, -1, &stStmt.p, NULL);
    if (rc != SQLITE_OK) {
        LogOutput(KGLOG_WARNING, "Internal_ExecuteQuery: prepare failed for SQL: %s, error=%d\n", szSQL ? szSQL : "(null)", rc);
        return -1;
    }

    if (!cbFillParams(this, stStmt.p, pState)) {
        LogOutput(KGLOG_WARNING, "Internal_ExecuteQuery: binding parameters failed for SQL: %s\n", szSQL ? szSQL : "(null)");
        return -1;
    }

    int iRowCount = 0;
    while (sqlite3_step(stStmt.p) == SQLITE_ROW) {
        if (!cbRow(this, stStmt.p, pState)) {
            LogOutput(KGLOG_DEBUG, "Internal_ExecuteQuery: row callback stopped at row %d.\n", iRowCount);
            break;
        }
        ++iRowCount;
    }

    LogOutput(KGLOG_DEBUG, "Internal_ExecuteQuery: executed SQL: %s, rows returned: %d\n", szSQL ? szSQL : "(null)", iRowCount);
    return iRowCount;
}

Sqlite3DatabaseLuabackend.h

cpp 复制代码
#pragma once

#include <atomic>
#include <mutex>
#include <deque>

#include "JString.h"
#include "KThread.h"
#include "KLuaScriptData.h"

struct SQLITE3_DATABASE_PROTOCOL
{
	DWORD			dwScriptID;
	int64_t			nQueryID;
	SharedString	strFunctionName; // 特殊用法,不要模仿
	KG_BOOL			bSelectFoundRows;
	KG_BOOL			bGetAffectedRows;
	KG_BOOL			bGetFiledsName;
	KG_BOOL			bFiledsNameAsKey;
	int				nUserDataLuaRef;
	size_t			uDataLen;
};

struct SQLITE3_DATABASE_USER_QUERY_REQUEST : SQLITE3_DATABASE_PROTOCOL
{
	BYTE			byData[0];
};

struct SQLITE3_DATABASE_USER_QUERY_RESPOND : SQLITE3_DATABASE_PROTOCOL
{
	KG_BOOL			bResult;
	int				nFiledsCount;
	int				nRowCount;
	int				nFoundRows;
	int				nAffectedRows;
	BYTE			byData[0];
};

class Sqlite3Database;

class Sqlite3DatabaseLuabackend : public ILuaObject
{
    typedef std::mutex										SynchronizedObject;
    typedef std::lock_guard<SynchronizedObject>				SynchronizedObjectScope;

public:
    typedef enum : uint8_t 
	{
        ERROR_NOERROR  = 0,
        ERROR_SQL,
        ERROR_PARAM,
        ERROR_RELEASE,
        ERROR_NOT_AVAILABLE,
		ERROR_EXECUTE_QUERY,
        ERROR_EXECUTE_NON_QUERY,
    }                                                       ERRORS;

	Sqlite3DatabaseLuabackend() noexcept;
    virtual ~Sqlite3DatabaseLuabackend() noexcept;

    static int64_t											GetCurrentThreadId() noexcept;

    KG_BOOL                                                 PushRequest(IKG_Buffer* pRequestBuffer) noexcept;

	void													Activate() noexcept { ExecuteAllRespond(); }

	KG_BOOL													Init() noexcept;

	void													UnInit() noexcept { Finalize(); }

	bool													IsAvailable() noexcept;

public:
	DECLARE_LUA_CLASS(Sqlite3DatabaseLuabackend);

	int														LuaQuery(lua_State* L);

private:
    IKG_Buffer*                                             PopRequest() noexcept;
	IKG_Buffer*												PopRespond() noexcept;

    void                                                    Finalize() noexcept;
	int														ExecuteAllRequests() noexcept;

	KG_BOOL													PushRespond(IKG_Buffer* pRequestBuffer) noexcept;

private:
    KG_BOOL                                                 ExecuteRequest(IKG_Buffer* pRequestBuffer) noexcept;
	KG_BOOL													ExecuteQuery(SQLITE3_DATABASE_USER_QUERY_REQUEST* pRequest, const char* szSQL) noexcept;
	KG_BOOL													ExecuteNonQuery(SQLITE3_DATABASE_USER_QUERY_REQUEST* pRequest, const char* szSQL) noexcept;

private:
	IKG_Buffer*												NewRespondBuffer(ERRORS eError, SQLITE3_DATABASE_USER_QUERY_REQUEST* pRequest, size_t uRespondSize) noexcept;

	bool													LuaRegisterObject() noexcept;

private:
	int														ExecuteAllRespond() noexcept;
	bool													ExecuteRespond(IKG_Buffer* pRespondBuffer) noexcept;

private:
    SynchronizedObject										m_SyncObjReq_;		// 请求同步
	SynchronizedObject										m_SyncObjRep_;		// 响应同步

	bool													m_bDisposed_;		// 已经释放
	int64_t													m_nQueryID_;

    std::shared_ptr<Sqlite3Database>						m_DB_;				// SQLITE3本地文件数据库
    std::deque<IKG_Buffer*>						            m_RequestDeque_;	// 查询
	std::deque<IKG_Buffer*>									m_RespondDeque_;	// 响应

	KThread													m_WorkThread_;
	SharedString											m_str_sqlite3;
	SharedString											m_str_bResult;
	SharedString											m_str_nQueryID;
	SharedString											m_str_szError;
	SharedString											m_str_nFoundRows;
	SharedString											m_str_nAffectedRows;
	SharedString											m_str_nFiledsCount;
	SharedString											m_str_nRowCount;
	SharedString											m_str_Fileds;
	SharedString											m_str_Rows;
};

Sqlite3DatabaseLuabackend.cpp

cpp 复制代码
#include "stdafx.h"
#include "SqliteDatabase.h"
#include "SqliteDatabaseLuabackend.h"
#include "DatabaseInteAuxiliary.h"
#include "TypeTraitsAuxiliary.h"

#include "KG_Memory.h"

#include <list>
#include <sstream>
#include <vector>

#include "sqlite3/sqlite3.h"

// SQLite 数据库文件名
static constexpr const char* SQLITE_DATABASE_DB_FILE_NMAE = "game.db";

/**
 * @brief 构造函数,初始化成员变量并创建 SqliteDatabase 对象
 */
SqliteDatabaseLuabackend::SqliteDatabaseLuabackend() noexcept
    : m_bDisposed_(false)
    , m_nQueryID_(0)
    , m_str_sqlite3(SHARED_STATIC_STRING("sqlite"))
    , m_str_bResult(SHARED_STATIC_STRING("bResult"))
    , m_str_nQueryID(SHARED_STATIC_STRING("nQueryID"))
    , m_str_szError(SHARED_STATIC_STRING("szError"))
    , m_str_nFoundRows(SHARED_STATIC_STRING("nFoundRows"))
    , m_str_nAffectedRows(SHARED_STATIC_STRING("nAffectedRows"))
    , m_str_nFiledsCount(SHARED_STATIC_STRING("nFiledsCount"))
    , m_str_nRowCount(SHARED_STATIC_STRING("nRowCount"))
    , m_str_Fileds(SHARED_STATIC_STRING("Fileds"))
    , m_str_Rows(SHARED_STATIC_STRING("Rows"))
{
    m_DB_ = std::make_shared<SqliteDatabase>();
}

/**
 * @brief 析构函数,调用 Finalize 清理资源
 */
SqliteDatabaseLuabackend::~SqliteDatabaseLuabackend()
{
    Finalize();
}

/**
 * @brief 释放资源,停止工作线程,清空请求/响应队列
 */
void SqliteDatabaseLuabackend::Finalize() noexcept
{
    std::deque<IKG_Buffer*> dqBuffersArray[2];
    m_bDisposed_ = true;               // 标记已释放,阻止新请求入队
    m_WorkThread_.Destroy();           // 等待工作线程退出

    // 将请求队列转移到局部变量,便于释放
    for (SynchronizedObjectScope _(m_SyncObjReq_);;)
    {
        dqBuffersArray[0] = std::move(m_RequestDeque_);
        m_RequestDeque_.clear();
        break;
    }

    // 将响应队列转移到局部变量,便于释放
    for (SynchronizedObjectScope _(m_SyncObjRep_);;)
    {
        dqBuffersArray[1] = std::move(m_RespondDeque_);
        m_RespondDeque_.clear();
        break;
    }

    // 遍历并释放未处理的请求和响应,打印警告日志
    static constexpr const char* acszUnprocessedErrors[2] = {
        "Unprocessed DB request: dwScriptID=%u, nQueryID=%lld, strFunctionName=%s" ,
        "Unprocessed DB respond: dwScriptID=%u, nQueryID=%lld, strFunctionName=%s"
    };
    for (int i = 0; i < arraysizeof(dqBuffersArray); ++i)
    {
        std::deque<IKG_Buffer*>& dqBuffers = dqBuffersArray[i];
        for (;;)
        {
            auto tail = dqBuffers.begin();
            auto endl = dqBuffers.end();
            if (tail == endl)
            {
                break;
            }

            IKG_Buffer* pBuffer = *tail;
            dqBuffers.erase(tail);

            SQLITE_DATABASE_PROTOCOL* pProtocol = (SQLITE_DATABASE_PROTOCOL*)pBuffer->GetData();
            // 注意:SharedString 在这里会被自动释放,因为 IUnknownAutodeleter 会调用 Release
            IUnknownAutodeleter<SharedString> oSharedStringAutodeleter{ &pProtocol->strFunctionName };

            LogOutput(KGLOG_WARNING, acszUnprocessedErrors[i], pProtocol->dwScriptID, pProtocol->nQueryID, pProtocol->strFunctionName.Get());
            KG_COM_RELEASE(pBuffer);
        }
    }
}

/**
 * @brief 从请求队列中弹出一个请求包(线程安全)
 * @return 请求包指针,队列空时返回 NULL
 */
IKG_Buffer* SqliteDatabaseLuabackend::PopRequest() noexcept
{
    IKG_Buffer* request = NULL;
    for (SynchronizedObjectScope _(m_SyncObjReq_);;)
    {
        auto tail = m_RequestDeque_.begin();
        auto endl = m_RequestDeque_.end();

        if (tail == endl)
        {
            return NULL;
        }

        request = *tail;
        m_RequestDeque_.erase(tail);

        return request;
    }
}

/**
 * @brief 从响应队列中弹出一个响应包(线程安全)
 * @return 响应包指针,队列空时返回 NULL
 */
IKG_Buffer* SqliteDatabaseLuabackend::PopRespond() noexcept
{
    for (;;)
    {
        SynchronizedObjectScope _(m_SyncObjRep_);
        auto tail = m_RespondDeque_.begin();
        auto endl = m_RespondDeque_.end();
        if (tail == endl)
        {
            return NULL;
        }

        IKG_Buffer* pBuffer = *tail;
        m_RespondDeque_.erase(tail);

        return pBuffer;
    }
}

/**
 * @brief 工作线程主循环:持续处理请求队列中的所有请求
 * @return 0 表示处理了至少一个请求,10 表示队列空且线程应短暂休眠
 */
int SqliteDatabaseLuabackend::ExecuteAllRequests() noexcept
{
    if (!IsAvailable())
    {
        return -1;
    }

    int events = 0;
    for (;;)
    {
        IKG_Buffer* request = PopRequest();
        if (NULL == request)
        {
            // 队列空,返回 0 或 10 供调度线程决定是否休眠
            return (events > 0) ? 0 : 10;
        }

        ++events;
        ExecuteRequest(request);

        KG_COM_RELEASE(request);   // 释放请求包(引用计数减1)
    }
}

/**
 * @brief 获取当前线程 ID(用于调试/日志,兼容各平台)
 * @return 线程 ID 的 int64 表示
 */
int64_t SqliteDatabaseLuabackend::GetCurrentThreadId() noexcept
{
    auto stl_thread_id = std::this_thread::get_id();
    // 将 std::thread::id 视为字节序列转换为整数,兼容各种实现
    return *reinterpret_cast<const int64_t*>(&reinterpret_cast<const char&>(stl_thread_id));
}

/**
 * @brief 判断字符串是否为空或 NULL
 */
static inline bool IsNullOrEmpty(const char* s) noexcept
{
    return (NULL == s) || ('\x0' == *s);
}

/**
 * @brief 将 Lua 发来的查询请求加入请求队列(线程安全)
 * @param pRequestBuffer 包含 SQLITE_DATABASE_USER_QUERY_REQUEST 的缓冲区
 * @return 成功返回 true,失败返回 false 并推送错误响应
 */
KG_BOOL SqliteDatabaseLuabackend::PushRequest(IKG_Buffer* pRequestBuffer) noexcept
{
    ERRORS error = ERROR_RELEASE;
    SQLITE_DATABASE_USER_QUERY_REQUEST* pRequest = NULL;

    KGLOG_PROCESS_ERROR(!m_bDisposed_);

    error = ERROR_NOT_AVAILABLE;
    KGLOG_PROCESS_ERROR(m_DB_->IsAvailable());

    error = ERROR_PARAM;
    KGLOG_PROCESS_ERROR(NULL != pRequestBuffer);

    BYTE* pbyData = (BYTE*)pRequestBuffer->GetData();
    unsigned int uDataLen = pRequestBuffer->GetSize();

    KGLOG_PROCESS_ERROR(NULL != pbyData && uDataLen >= sizeof(SQLITE_DATABASE_USER_QUERY_REQUEST));

    pRequest = reinterpret_cast<SQLITE_DATABASE_USER_QUERY_REQUEST*>(pbyData);
    const char* szSQL = reinterpret_cast<const char*>(pRequest->byData);

    if (IsNullOrEmpty(szSQL))
    {
        error = ERROR_SQL;
        goto Exit0;
    }

    pRequestBuffer->AddRef();               // 增加引用,因为队列会持有它
    error = ERROR_NOERROR;

    for (SynchronizedObjectScope _(m_SyncObjReq_);;)
    {
        m_RequestDeque_.emplace_back(pRequestBuffer);
        break;
    }

Exit0:
    if (ERROR_NOERROR == error)
    {
        return true;
    }

    // 失败时立即构造错误响应并推送,避免请求丢失
    PushRespond(NewRespondBuffer(error, pRequest, sizeof(SQLITE_DATABASE_USER_QUERY_RESPOND)));
    return false;
}

/**
 * @brief 初始化:打开数据库、注册 Lua 对象、创建工作线程
 * @return 成功返回 true,失败返回 false
 */
KG_BOOL SqliteDatabaseLuabackend::Init() noexcept
{
    if (m_bDisposed_)
    {
        return false;
    }

    if (IsAvailable())
    {
        return true;
    }

    KGLOG_PROCESS_ERROR(m_DB_->Open(SQLITE_DATABASE_DB_FILE_NMAE));
    LogOutput(KGLOG_INFO, "Init: database opened successfully.\n");

    KGLOG_PROCESS_ERROR(LuaRegisterObject());   // 将对象注册到 Lua 全局变量
    LogOutput(KGLOG_INFO, "Init: Lua object registered.\n");

    // 创建工作线程,执行 ExecuteAllRequests
    int nRetCode = m_WorkThread_.Create(
        [](void* pvParam) noexcept
        {
            SqliteDatabaseLuabackend* RCX = (SqliteDatabaseLuabackend*)pvParam;
            return (NULL != RCX) ? RCX->ExecuteAllRequests() : -1;
        }, this);
    KGLOG_PROCESS_ERROR(nRetCode);

    LogOutput(KGLOG_INFO, "Init: work thread created.\n");
    return true;

Exit0:
    LogOutput(KGLOG_ERR, "Init: failed.\n");
    return false;
}

/**
 * @brief 检查数据库是否可用(未释放且 SQLite 连接有效)
 */
bool SqliteDatabaseLuabackend::IsAvailable() noexcept
{
    return (!m_bDisposed_) && m_DB_->IsAvailable();
}

/**
 * @brief 主线程中调用,处理所有待处理的响应(激活 Lua 回调)
 * @return 处理的响应数量,出错返回 -1
 */
int SqliteDatabaseLuabackend::ExecuteAllRespond() noexcept
{
    if (!IsAvailable())
    {
        return -1;
    }

    int events = 0;
    for (;;)
    {
        IKG_Buffer* pRespondBuffer = PopRespond();
        if (NULL == pRespondBuffer)
        {
            break;
        }

        IUnknownAutodeleter<> oRespondAutodeleter{ pRespondBuffer };   // 确保最终释放
        if (!ExecuteRespond(pRespondBuffer))
        {
            break;
        }
        ++events;
    }

    return events;
}

/**
 * @brief 执行一个响应包:调用 DatabaseInteAuxiliary 解析并回调 Lua
 * @param pRespondBuffer 响应缓冲区
 * @return 成功返回 true
 */
bool SqliteDatabaseLuabackend::ExecuteRespond(IKG_Buffer* pRespondBuffer) noexcept
{
    BYTE* pbyData = (BYTE*)pRespondBuffer->GetData();
    KGLOG_PROCESS_ERROR(NULL != pbyData);

    size_t uDataLen = pRespondBuffer->GetSize();
    KGLOG_PROCESS_ERROR(uDataLen >= sizeof(SQLITE_DATABASE_USER_QUERY_RESPOND));

    SQLITE_DATABASE_USER_QUERY_RESPOND* pRespond = (SQLITE_DATABASE_USER_QUERY_RESPOND*)pbyData;

    // 调用公共解析函数,将响应数据转换为 Lua 表并触发回调
    DatabaseInteAuxiliary::ExecuteRespond<SQLITE_DATABASE_USER_QUERY_RESPOND>(pbyData,
        uDataLen,
        m_str_bResult,
        m_str_nQueryID,
        m_str_szError,
        m_str_nFoundRows,
        m_str_nAffectedRows,
        m_str_nFiledsCount,
        m_str_nRowCount,
        m_str_Fileds,
        m_str_Rows);
    return true;

Exit0:
    return false;
}

/**
 * @brief 将响应包推入响应队列(线程安全)
 * @param pRequestBuffer 响应缓冲区(已包含 SQLITE_DATABASE_USER_QUERY_RESPOND)
 * @return 始终返回 true(失败时已经打印警告)
 */
KG_BOOL SqliteDatabaseLuabackend::PushRespond(IKG_Buffer* pRequestBuffer) noexcept
{
    if (NULL == pRequestBuffer)
    {
        return false;
    }

    SQLITE_DATABASE_USER_QUERY_RESPOND* pRespond = (SQLITE_DATABASE_USER_QUERY_RESPOND*)pRequestBuffer->GetData();

    SynchronizedObjectScope _(m_SyncObjRep_);
    m_RespondDeque_.emplace_back(pRequestBuffer);
    return true;
}

/**
 * @brief 执行非查询 SQL(INSERT/UPDATE/DELETE 等)
 * @param pRequest 原始请求结构
 * @param szSQL    执行的 SQL 语句
 * @return 成功返回 true,失败返回 false
 */
KG_BOOL SqliteDatabaseLuabackend::ExecuteNonQuery(SQLITE_DATABASE_USER_QUERY_REQUEST* pRequest, const char* szSQL) noexcept
{
    int nonquery = m_DB_->ExecuteNonQuery(szSQL, (const char**)NULL, 0);
    if (0 > nonquery)
    {
        PushRespond(NewRespondBuffer(ERROR_EXECUTE_NON_QUERY, pRequest, sizeof(SQLITE_DATABASE_USER_QUERY_RESPOND)));
        return false;
    }

    IKG_Buffer* pResonpodBuffer = NewRespondBuffer(ERROR_NOERROR, pRequest, sizeof(SQLITE_DATABASE_USER_QUERY_RESPOND));
    if (NULL == pResonpodBuffer)
    {
        return false;
    }

    SQLITE_DATABASE_USER_QUERY_RESPOND* pRespond = (SQLITE_DATABASE_USER_QUERY_RESPOND*)pResonpodBuffer->GetData();
    pRespond->bResult = true;
    pRespond->nAffectedRows = nonquery;

    return PushRespond(pResonpodBuffer);
}

/**
 * @brief 处理一个请求(分发到查询或非查询)
 * @param pRequestBuffer 请求缓冲区
 * @return 成功返回 true
 */
KG_BOOL SqliteDatabaseLuabackend::ExecuteRequest(IKG_Buffer* pRequestBuffer) noexcept
{
    SQLITE_DATABASE_USER_QUERY_REQUEST* pRequest = (SQLITE_DATABASE_USER_QUERY_REQUEST*)pRequestBuffer->GetData();
    const char* szSQL = reinterpret_cast<const char*>(pRequest->byData);

    if (!m_DB_->IsAvailable())
    {
        PushRespond(NewRespondBuffer(ERROR_NOT_AVAILABLE, pRequest, sizeof(SQLITE_DATABASE_USER_QUERY_RESPOND)));
        return false;
    }

    // 如果需要支持非查询,可在此处根据 SQL 类型调用 ExecuteNonQuery
    if (ExecuteQuery(pRequest, szSQL))
    {
        return true;
    }

    LogOutput(KGLOG_ERR, "ERROR(false) <%s> at line %d in %s\n", szSQL, __LINE__, KG_FUNCTION);
    return false;
}

/**
 * @brief 执行查询 SQL(SELECT),将结果集转换为自定义二进制格式
 * @param pRequest 原始请求结构
 * @param szSQL    SQL 语句
 * @return 成功返回 true
 */
KG_BOOL SqliteDatabaseLuabackend::ExecuteQuery(SQLITE_DATABASE_USER_QUERY_REQUEST* pRequest, const char* szSQL) noexcept
{
    struct ExecuteQueryContext
    {
        std::vector<uint8_t> vtPayload;   // 二进制负载(字段名+行数据)
        uint32_t ulRowNum = 0;            // 返回行数
        int32_t iColumnCount = 0;         // 列数
    } stExecuteQueryContext;

    std::vector<std::string> vtParameters{};   // 参数列表,当前无参数
    int nRowNum = m_DB_->ExecuteQuery(szSQL, vtParameters.begin(), vtParameters.end(),
        [pRequest, &stExecuteQueryContext](SqliteDatabase*, sqlite3_stmt* stmt) noexcept -> bool
        {
            auto& vt = stExecuteQueryContext.vtPayload;
            // 辅助 lambda:写入长度+数据
            auto vt_write = [&vt](const void* pData, uint32_t ulDataSize) noexcept
                {
                    vt.insert(vt.end(), reinterpret_cast<const uint8_t*>(&ulDataSize),
                        reinterpret_cast<const uint8_t*>(&ulDataSize) + sizeof(uint32_t));
                    if ((0 < ulDataSize) && (NULL != pData))
                    {
                        vt.insert(vt.end(), reinterpret_cast<const uint8_t*>(pData),
                            reinterpret_cast<const uint8_t*>(pData) + ulDataSize);
                    }
                };

            // 获取列数(仅第一次调用时)
            int32_t iColumnCount = sqlite3_column_count(stmt);
            if (0 > iColumnCount)
            {
                iColumnCount = 0;
            }
            if (0 == stExecuteQueryContext.iColumnCount)
            {
                stExecuteQueryContext.iColumnCount = iColumnCount;
                // 如果请求了字段名,则直接写入字段名列表(每个字段名:长度+名称),不写入额外的列数前缀
                // 这与原始 DataBase 的协议完全一致
                if (pRequest->bGetFiledsName)
                {
                    for (int i = 0; i < iColumnCount; ++i)
                    {
                        const char* szColumnName = sqlite3_column_name(stmt, i);
                        if (NULL == szColumnName)
                        {
                            szColumnName = "";
                        }
                        size_t ulColumnNameSize = strlen(szColumnName);
                        vt_write(szColumnName, static_cast<uint32_t>(ulColumnNameSize));
                    }
                }
            }

            // 写入一行数据
            char szTextBuf[127];
            for (int i = 0; i < iColumnCount; ++i)
            {
                int iColumnType = sqlite3_column_type(stmt, i);
                switch (iColumnType)
                {
                case SQLITE_INTEGER:
                {
                    size_t ulColumnValueSize = snprintf(szTextBuf, sizeof(szTextBuf), "%lld", sqlite3_column_int64(stmt, i));
                    vt_write(szTextBuf, static_cast<uint32_t>(ulColumnValueSize));
                    break;
                }
                case SQLITE_FLOAT:
                {
                    size_t ulColumnValueSize = snprintf(szTextBuf, sizeof(szTextBuf), "%lf", sqlite3_column_double(stmt, i));
                    vt_write(szTextBuf, static_cast<uint32_t>(ulColumnValueSize));
                    break;
                }
                case SQLITE_TEXT:
                {
                    const char* szColumnText = (const char*)sqlite3_column_text(stmt, i);
                    if (NULL == szColumnText)
                    {
                        szColumnText = "";
                    }
                    vt_write(szColumnText, static_cast<uint32_t>(strlen(szColumnText)));
                    break;
                }
                case SQLITE_BLOB:
                {
                    const void* pColumnBlobData = sqlite3_column_blob(stmt, i);
                    int iColumnValueSize = sqlite3_column_bytes(stmt, i);
                    if ((NULL != pColumnBlobData) && (0 < iColumnValueSize))
                    {
                        vt_write(pColumnBlobData, static_cast<uint32_t>(iColumnValueSize));
                    }
                    else
                    {
                        vt_write(NULL, 0);
                    }
                    break;
                }
                default: // SQLITE_NULL
                    vt_write(NULL, 0);
                    break;
                }
            }
            ++stExecuteQueryContext.ulRowNum;
            return true;   // 继续获取下一行
        });

    if (0 > nRowNum)
    {
        PushRespond(NewRespondBuffer(ERROR_EXECUTE_QUERY, pRequest, sizeof(SQLITE_DATABASE_USER_QUERY_RESPOND)));
        return false;
    }

    size_t ulPayloadSize = stExecuteQueryContext.vtPayload.size();
    size_t ulRespondSize = sizeof(SQLITE_DATABASE_USER_QUERY_RESPOND) + ulPayloadSize;
    IKG_Buffer* pRespondBuffer = NewRespondBuffer(ERROR_NOERROR, pRequest, ulRespondSize);
    if (NULL == pRespondBuffer)
    {
        return false;
    }

    SQLITE_DATABASE_USER_QUERY_RESPOND* pRespond = (SQLITE_DATABASE_USER_QUERY_RESPOND*)pRespondBuffer->GetData();
    if (0 < ulPayloadSize)
    {
        memcpy(pRespond->byData, stExecuteQueryContext.vtPayload.data(), ulPayloadSize);
    }

    pRespond->bResult = true;
    pRespond->nRowCount = stExecuteQueryContext.ulRowNum;
    pRespond->nFiledsCount = stExecuteQueryContext.iColumnCount;
    pRespond->uDataLen = ulPayloadSize;

    if (pRequest->bGetAffectedRows)
    {
        pRespond->nAffectedRows = m_DB_->GetAffectedRows();
    }

    return PushRespond(pRespondBuffer);
}

/**
 * @brief 创建响应缓冲区,并填充基本字段(请求信息、错误码等)
 * @param eError      错误码(ERROR_NOERROR 表示成功)
 * @param pRequest    原始请求
 * @param uRespondSize 响应缓冲区总大小
 * @return 新创建的 IKG_Buffer 对象,失败返回 NULL
 */
IKG_Buffer* SqliteDatabaseLuabackend::NewRespondBuffer(ERRORS eError, SQLITE_DATABASE_USER_QUERY_REQUEST* pRequest, size_t uRespondSize) noexcept
{
    if ((NULL == pRequest) || (uRespondSize < sizeof(SQLITE_DATABASE_USER_QUERY_RESPOND)))
    {
        return NULL;
    }

    IKG_Buffer* piBuffer = CreateMemoryBuffer(uRespondSize);
    if (NULL == piBuffer)
    {
        KGLOG_CHECK_ERROR(NULL != piBuffer);
        return NULL;
    }

    SQLITE_DATABASE_USER_QUERY_RESPOND* pRespond = (SQLITE_DATABASE_USER_QUERY_RESPOND*)piBuffer->GetData();

    pRespond->dwScriptID = pRequest->dwScriptID;
    pRespond->nQueryID = pRequest->nQueryID;
    // 危险操作:直接拷贝 SharedString 对象,必须配合引用计数管理。
    // 接收方(ExecuteRespond)会通过 IUnknownAutodeleter 释放一次,此处也需保持引用计数平衡。
    // 由于 pRequest 的 strFunctionName 已经 AddRef 过(在 LuaQuery 中),这里拷贝后两者共享同一份引用。
    memcpy(&pRespond->strFunctionName, &pRequest->strFunctionName, sizeof(pRespond->strFunctionName));

    pRespond->bResult = true;
    pRespond->bSelectFoundRows = pRequest->bSelectFoundRows;
    pRespond->bGetAffectedRows = pRequest->bGetAffectedRows;
    pRespond->bGetFiledsName = pRequest->bGetFiledsName;
    pRespond->bFiledsNameAsKey = pRequest->bFiledsNameAsKey;
    pRespond->nFiledsCount = 0;
    pRespond->nRowCount = 0;
    pRespond->nAffectedRows = 0;
    pRespond->nUserDataLuaRef = pRequest->nUserDataLuaRef;
    pRespond->uDataLen = uRespondSize - sizeof(SQLITE_DATABASE_USER_QUERY_RESPOND);

    return piBuffer;
}

/**
 * @brief 将 SqliteDatabaseLuabackend 对象注册到 Lua 全局变量
 * @return 成功返回 true
 */
bool SqliteDatabaseLuabackend::LuaRegisterObject() noexcept
{
    int nResult = false;
    lua_State* L = NULL;

    KGLOG_PROCESS_ERROR(g_pLuaScriptEx);

    L = g_pLuaScriptEx->GetLuaState();
    KGLOG_PROCESS_ERROR(NULL != L);

    // 注册类,Luna 会生成元表并绑定方法
    Luna<SqliteDatabaseLuabackend>::Register(L);

    // 将全局变量 sqlite3 设置为该对象
    GetLuaObj(L);
    m_str_sqlite3.SetGlobal(L);
    nResult = true;

Exit0:
    if (!nResult)
    {
        LogOutput(KGLOG_ERR, "LuaRegisterObject: registration failed.\n");
    }
    return nResult;
}

/**
 * @brief Lua 可调用的查询接口,模拟 DataBase:Query
 * @param L Lua 状态机
 * @return Lua 返回值数量(1:nQueryID)
 */
int SqliteDatabaseLuabackend::LuaQuery(lua_State* L)
{
    SharedString strFunctionName;
    int nResult = 0;
    int nTopIndex = lua_gettop(L);
    bool bAddFuncNameRef = false;
    IKG_Buffer* piBuffer = NULL;
    const char* pcszSql = NULL;
    KGLOG_PROCESS_ERROR(4 <= nTopIndex);   // 至少需要 4 个参数: self, scriptData, funcName, sql

    LuaScriptData* pLuaScriptData = Luna<LuaScriptData>::ToObject(L, 2);
    KGLOG_PROCESS_ERROR(NULL != pLuaScriptData);

    size_t uSqlLength = 0;
    strFunctionName.Set(L, 3);

    pcszSql = lua_tolstring(L, 4, &uSqlLength);
    KGLOG_PROCESS_ERROR(NULL != pcszSql);

    ++uSqlLength;   // 包含结尾 '\0'
    piBuffer = CreateMemoryBuffer(uSqlLength + sizeof(SQLITE_DATABASE_USER_QUERY_REQUEST));
    KGLOG_PROCESS_ERROR(NULL != piBuffer);

    SQLITE_DATABASE_USER_QUERY_REQUEST* pRequest = (SQLITE_DATABASE_USER_QUERY_REQUEST*)piBuffer->GetData();
    pRequest->dwScriptID = pLuaScriptData->m_dwID;
    pRequest->nQueryID = m_nQueryID_++;
    pRequest->nUserDataLuaRef = LUA_NOREF;

    // 增加 SharedString 引用计数,以便后续拷贝使用
    strFunctionName.AddRef();
    bAddFuncNameRef = true;
    memcpy(&pRequest->strFunctionName, &strFunctionName, sizeof(pRequest->strFunctionName));

    // 解析 Lua 传入的可选参数
    pRequest->bSelectFoundRows = false;
    pRequest->bGetFiledsName = false;
    pRequest->bFiledsNameAsKey = false;
    if (4 < nTopIndex)
    {
        pRequest->bSelectFoundRows = lua_toboolean(L, 5);
        if (5 < nTopIndex)
        {
            pRequest->bGetFiledsName = lua_toboolean(L, 6);
            if (6 < nTopIndex)
            {
                pRequest->bFiledsNameAsKey = lua_toboolean(L, 7);
                if (7 < nTopIndex)
                {
                    lua_pushvalue(L, 8);
                    pRequest->nUserDataLuaRef = luaL_ref(L, LUA_REGISTRYINDEX);
                }
            }
        }
    }

    pRequest->uDataLen = uSqlLength;
    memcpy(pRequest->byData, pcszSql, uSqlLength);

    // 将请求推入队列,队列内部会 AddRef,因此我们稍后需要释放本地的 piBuffer
    int nRetCode = PushRequest(piBuffer);
    KGLOG_PROCESS_ERROR(nRetCode);

    // 成功:返回 nQueryID 给 Lua
    lua_pushinteger(L, pRequest->nQueryID);
    nResult = 1;                        // 返回值个数

Exit0:
    // 失败时,需显示减少函数名引用计数
    bool bExcept = 1 != nResult;
    if (bExcept && bAddFuncNameRef)
    {
        strFunctionName.Release(); // luaS_release_cstr
    }

    KG_COM_RELEASE(piBuffer);           // 释放本地缓冲区(队列已持有引用,释放后引用计数减1,仍由队列持有)
    if (bExcept && (NULL != pcszSql))
    {
        LogOutput(KGLOG_ERR, "ERROR(false) <%s> at line %d in %s\n", pcszSql, __LINE__, KG_FUNCTION);
    }

    return nResult;                     // 失败返回 0(未向栈推值)
}

// 注册 Lua 方法
DEFINE_LUA_COLON_FUNC(SqliteDatabaseLuabackend, Query)
DEFINE_LUA_CLASS_BEGIN(SqliteDatabaseLuabackend)
REGISTER_LUA_COLON_FUNC(SqliteDatabaseLuabackend, Query)
DEFINE_LUA_CLASS_END(SqliteDatabaseLuabackend)

DatabaseInteAuxiliary.h

cpp 复制代码
#pragma once

#include "JString.h"
#include "KLuaScriptData.h"

/**
 * @brief 数据库交互辅助类,提供通用的响应解析功能
 * @note 该类与具体数据库实现无关,仅负责将二进制响应转换为 Lua 表并调用回调
 */
class DatabaseInteAuxiliary
{
public:
    /**
     * @brief 执行数据库响应:解析二进制数据,构建 Lua 表,并调用 Lua 函数
     * @tparam T_DATABASE_USER_QUERY_RESPOND 响应结构体类型(必须包含 bResult、nFiledsCount、nRowCount、byData 等成员)
     * @param pbyData                       响应数据首地址
     * @param uDataLen                      数据总长度
     * @param m_str_bResult                 Lua 字符串键 "bResult"
     * @param m_str_nQueryID                Lua 字符串键 "nQueryID"
     * @param m_str_szError                 Lua 字符串键 "szError"
     * @param m_str_nFoundRows              Lua 字符串键 "nFoundRows"
     * @param m_str_nAffectedRows           Lua 字符串键 "nAffectedRows"
     * @param m_str_nFiledsCount            Lua 字符串键 "nFiledsCount"
     * @param m_str_nRowCount               Lua 字符串键 "nRowCount"
     * @param m_str_Fileds                  Lua 字符串键 "Fileds"
     * @param m_str_Rows                    Lua 字符串键 "Rows"
     */
    template <typename T_DATABASE_USER_QUERY_RESPOND>
    static void                             ExecuteRespond(
        BYTE*                               pbyData,
        size_t                              uDataLen,
        SharedString                        m_str_bResult,
        SharedString                        m_str_nQueryID,
        SharedString                        m_str_szError,
        SharedString                        m_str_nFoundRows,
        SharedString                        m_str_nAffectedRows,
        SharedString                        m_str_nFiledsCount,
        SharedString                        m_str_nRowCount,
        SharedString                        m_str_Fileds,
        SharedString                        m_str_Rows) noexcept
    {
        int nRetCode = false;
        int nTopIndex = 0;
        const char* pszResult = NULL;
        LuaScriptEx* pLuaScriptEx = g_pLuaScriptEx;
        lua_State* L = NULL;
        SharedStringArray strFileds;
        T_DATABASE_USER_QUERY_RESPOND* pRespond = (T_DATABASE_USER_QUERY_RESPOND*)pbyData;

        // 自动管理 SharedString 的引用,确保函数退出时释放
        IUnknownAutodeleter<SharedString> oFunctionNameAutodeleter{ &pRespond->strFunctionName };

        KGLOG_PROCESS_ERROR(NULL != pLuaScriptEx);
        L = pLuaScriptEx->GetLuaState();
        KGLOG_PROCESS_ERROR(NULL != L);

        bool bSafeCallStarted = false;          // 是否已成功进入安全调用
        bool bSafeCallEnded = false;            // 是否已结束安全调用

        nRetCode = pLuaScriptEx->BeginSafeCallFunction(pRespond->dwScriptID, pRespond->strFunctionName, &nTopIndex);
        if (nRetCode)
        {
            bSafeCallStarted = true;
        }
        else
        {
            goto Exit0;
        }

        if (pRespond->bResult)
        {
            // 创建结果表
            lua_createtable(L, 0, 8);

            lua_pushinteger(L, pRespond->nQueryID);
            m_str_nQueryID.SetField(L, -2);

            lua_pushboolean(L, pRespond->bResult);
            m_str_bResult.SetField(L, -2);

            lua_pushinteger(L, pRespond->nFiledsCount);
            m_str_nFiledsCount.SetField(L, -2);

            lua_pushinteger(L, pRespond->nRowCount);
            m_str_nRowCount.SetField(L, -2);

            if (pRespond->bSelectFoundRows)
            {
                lua_pushinteger(L, pRespond->nFoundRows);
                m_str_nFoundRows.SetField(L, -2);
            }

            if (pRespond->bGetAffectedRows)
            {
                lua_pushinteger(L, pRespond->nAffectedRows);
                m_str_nAffectedRows.SetField(L, -2);
            }

            pszResult = (const char*)pRespond->byData;
            int nFields = pRespond->nFiledsCount;
            bool bFiledsNameAsKey = pRespond->bFiledsNameAsKey;

            strFileds.Reserve(nFields);

            // 如果请求了字段名,则读取字段名列表(格式:每个字段名长度+数据,无额外列数前缀)
            if (pRespond->bGetFiledsName)
            {
                for (int i = 0; i < nFields; ++i)
                {
                    // 边界检查
                    if ((pszResult + sizeof(uint32_t)) > ((const char*)pRespond->byData + pRespond->uDataLen))
                    {
                        goto Exit0;
                    }

                    uint32_t uLen = *((uint32_t*)pszResult);
                    pszResult += sizeof(uint32_t);
                    if ((pszResult + uLen) > ((const char*)pRespond->byData + pRespond->uDataLen))
                    {
                        goto Exit0;
                    }

                    strFileds.Append(SharedString(pszResult, uLen));
                    pszResult += uLen;
                }
            }

            // 构建 Rows 表(行列表)
            lua_createtable(L, pRespond->nRowCount, 0);
            for (int row = 1; row <= pRespond->nRowCount; ++row)
            {
                lua_createtable(L, 0, nFields);
                for (int col = 1; col <= nFields; ++col)
                {
                    // 读取每个单元格的长度和数据
                    if ((pszResult + sizeof(uint32_t)) > ((const char*)pRespond->byData + pRespond->uDataLen))
                    {
                        goto Exit0;
                    }

                    uint32_t uLen = *((uint32_t*)pszResult);
                    pszResult += sizeof(uint32_t);
                    if ((pszResult + uLen) > ((const char*)pRespond->byData + pRespond->uDataLen))
                    {
                        goto Exit0;
                    }

                    const char* pData = pszResult;
                    pszResult += uLen;

                    if (bFiledsNameAsKey && pRespond->bGetFiledsName)
                    {
                        // 使用字段名作为键(兼容原始 DataBase 的 bFiledsNameAsKey 模式)
                        strFileds[col - 1].SetField(L, -2);
                        lua_pushlstring(L, pData, uLen);
                        lua_settable(L, -3);
                    }
                    else
                    {
                        // 使用数字索引作为键
                        lua_pushlstring(L, pData, uLen);
                        lua_seti(L, -2, col);
                    }
                }
                lua_seti(L, -2, row);
            }
            m_str_Rows.SetField(L, -2);

            // 如果请求了字段名且不以字段名作为键,则填充 Fileds 表(字段名数组)
            if (pRespond->bGetFiledsName && (!bFiledsNameAsKey))
            {
                lua_createtable(L, nFields, 0);
                for (int i = 1; i <= nFields; ++i)
                {
                    lua_pushlstring(L, strFileds[i - 1].Get(), strFileds[i - 1].GetLength());
                    lua_seti(L, -2, i);
                }
                m_str_Fileds.SetField(L, -2);
            }
        }
        else
        {
            // 错误响应:仅包含 bResult, nQueryID, szError
            lua_createtable(L, 0, 3);
            lua_pushinteger(L, pRespond->nQueryID);
            m_str_nQueryID.SetField(L, -2);

            lua_pushboolean(L, pRespond->bResult);
            m_str_bResult.SetField(L, -2);

            lua_pushlstring(L, (const char*)pRespond->byData, pRespond->uDataLen);
            m_str_szError.SetField(L, -2);
        }

        pLuaScriptEx->AddParamCount();                     // 增加参数计数(结果表)
        if (LUA_NOREF != pRespond->nUserDataLuaRef)
        {
            pLuaScriptEx->PushRef(pRespond->nUserDataLuaRef); // 推送用户数据
        }

        nRetCode = pLuaScriptEx->SafeCallFunction(0, pRespond->strFunctionName);
        pLuaScriptEx->EndSafeCallFunction(nTopIndex);

        bSafeCallEnded = true;                             // 已主动结束
        KGLOG_PROCESS_ERROR(nRetCode);

    Exit0:
        // 释放用户数据 Lua 引用
        if (LUA_NOREF != pRespond->nUserDataLuaRef)
        {
            luaL_unref(L, LUA_REGISTRYINDEX, pRespond->nUserDataLuaRef);
        }

        // 如果安全调用已开始但尚未结束,则必须结束以恢复栈
        if (bSafeCallStarted && (!bSafeCallEnded))
        {
            pLuaScriptEx->EndSafeCallFunction(nTopIndex);
        }
    }
};

TypeTraitsAuxiliary.h

cpp 复制代码
#pragma once

#include <iostream>
#include <type_traits>

#include "KGPublic.h"

template <typename T = IUnknown>
class IUnknownAutodeleter
{
    template <typename, typename = void>
    struct has_release : std::false_type {};

    template <typename T>
    struct has_release<T, std::void_t<decltype(&T::Release)>>
        : std::is_member_function_pointer<decltype(&T::Release)> {};

    static_assert(std::is_base_of<IUnknown, T>::value || has_release<T>::value,
        "T must be derived from IUnknown or has Release function.");

public:
    IUnknownAutodeleter() noexcept : p_(NULL) {}
    IUnknownAutodeleter(T* p) noexcept : p_(p) {}
    IUnknownAutodeleter(const IUnknownAutodeleter&) = delete;
    IUnknownAutodeleter(IUnknownAutodeleter&& other) noexcept
        : p_(other.p_)
    {
        other.p_ = NULL;
    }
    ~IUnknownAutodeleter() noexcept
    {
        KG_COM_RELEASE(p_);
    }

    IUnknownAutodeleter&            operator=(IUnknownAutodeleter&& other) noexcept
    {
        if (this != &other)
        {
            KG_COM_RELEASE(p_);
            p_ = other.p_;
            other.p_ = NULL;
        }
        return *this;
    }

    IUnknownAutodeleter&            operator=(const IUnknownAutodeleter&) = delete;

    T*                              get() const noexcept { return p_; }

    // 交换(不释放旧指针)
    T*                              exchange(T* p = NULL) noexcept
    {
        T* old = p_;
        p_ = p;
        return old;
    }

    // 重置并释放旧指针
    void                            reset(T* p = NULL) noexcept
    {
        KG_COM_RELEASE(p_);
        p_ = p;
    }

private:
    T*                              p_;
};

template <typename T, int N>
constexpr int                                                               arraysizeof(T(&)[N]) noexcept {
    return N;
}
相关推荐
沉鱼.442 小时前
进制转换题
开发语言·c++·算法
今儿敲了吗2 小时前
49| 枚举排列
数据结构·c++·笔记·学习·算法
小李小李快乐不已2 小时前
docker(2)容器管理与镜像操作
运维·c++·docker·容器
hnlgzb2 小时前
安卓app体系中,room数据库和datastore是什么关系?有什么不一样?
android·数据库·oracle
book_longker2 小时前
postgresql 数据库的安装,配置,备份,恢复
数据库·postgresql
Elastic 中国社区官方博客2 小时前
从判断列表到训练好的 Learning to Rank( LTR )模型
大数据·数据库·人工智能·深度学习·elasticsearch·搜索引擎·全文检索
天若有情6732 小时前
从C++ RefInt到JS Object.defineProperty:吃透响应式监听的本质(学生视角)
开发语言·javascript·c++
Morwit2 小时前
【力扣hot100】 70. 爬楼梯
c++·算法·leetcode·职场和发展
我能坚持多久2 小时前
C++入门基础知识
开发语言·c++·学习