From 928f605c460d5798ac35f3ea0367cb22d4738cd4 Mon Sep 17 00:00:00 2001 From: iThorgrim Date: Wed, 22 Jan 2025 15:46:45 +0100 Subject: [PATCH] Feat: Add support for parameterized SQL queries with argument escaping --- src/LuaEngine/LuaEngine.cpp | 42 +++++++++++++++++++++++++++ src/LuaEngine/LuaEngine.h | 2 ++ src/LuaEngine/methods/GlobalMethods.h | 27 +++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/src/LuaEngine/LuaEngine.cpp b/src/LuaEngine/LuaEngine.cpp index 40cb155b3b..a2f312e77d 100644 --- a/src/LuaEngine/LuaEngine.cpp +++ b/src/LuaEngine/LuaEngine.cpp @@ -690,6 +690,48 @@ void Eluna::Push(lua_State* luastate, ObjectGuid const guid) ElunaTemplate::Push(luastate, new unsigned long long(guid.GetRawValue())); } +std::string Eluna::FormatQuery(lua_State* L, const char* query) +{ + int numArgs = lua_gettop(L); + std::string formattedQuery = query; + + size_t position = 0; + for (int i = 2; i <= numArgs; ++i) + { + std::string arg; + + if (lua_isnumber(L, i)) + { + arg = std::to_string(lua_tonumber(L, i)); + } + else if (lua_isstring(L, i)) + { + std::string value = lua_tostring(L, i); + for (size_t pos = 0; (pos = value.find('\'', pos)) != std::string::npos; pos += 2) + { + value.insert(pos, "'"); + } + arg = "'" + value + "'"; + } + else + { + luaL_error(L, "Unsupported argument type. Only numbers and strings are supported."); + return ""; + } + + position = formattedQuery.find("?", position); + if (position == std::string::npos) + { + luaL_error(L, "Mismatch between placeholders and arguments."); + return ""; + } + formattedQuery.replace(position, 1, arg); + position += arg.length(); + } + + return formattedQuery; +} + static int CheckIntegerRange(lua_State* luastate, int narg, int min, int max) { double value = luaL_checknumber(luastate, narg); diff --git a/src/LuaEngine/LuaEngine.h b/src/LuaEngine/LuaEngine.h index b6869f144e..d81888c6f6 100644 --- a/src/LuaEngine/LuaEngine.h +++ b/src/LuaEngine/LuaEngine.h @@ -261,6 +261,8 @@ class ELUNA_GAME_API Eluna { ElunaTemplate::Push(luastate, ptr); } + + static std::string FormatQuery(lua_State* L, const char* query); bool ExecuteCall(int params, int res); diff --git a/src/LuaEngine/methods/GlobalMethods.h b/src/LuaEngine/methods/GlobalMethods.h index d1f29f3e24..9d1c1ba9ca 100644 --- a/src/LuaEngine/methods/GlobalMethods.h +++ b/src/LuaEngine/methods/GlobalMethods.h @@ -1311,6 +1311,10 @@ namespace LuaGlobalFunctions { const char* query = Eluna::CHECKVAL(L, 1); + int numArgs = lua_gettop(L); + if (numArgs > 1) + query = Eluna::FormatQuery(L, query).c_str(); + ElunaQuery result = WorldDatabase.Query(query); if (result) Eluna::Push(L, new ElunaQuery(result)); @@ -1359,6 +1363,11 @@ namespace LuaGlobalFunctions int WorldDBExecute(lua_State* L) { const char* query = Eluna::CHECKVAL(L, 1); + + int numArgs = lua_gettop(L); + if (numArgs > 1) + query = Eluna::FormatQuery(L, query).c_str(); + WorldDatabase.Execute(query); return 0; } @@ -1379,6 +1388,10 @@ namespace LuaGlobalFunctions { const char* query = Eluna::CHECKVAL(L, 1); + int numArgs = lua_gettop(L); + if (numArgs > 1) + query = Eluna::FormatQuery(L, query).c_str(); + QueryResult result = CharacterDatabase.Query(query); if (result) Eluna::Push(L, new QueryResult(result)); @@ -1420,6 +1433,11 @@ namespace LuaGlobalFunctions int CharDBExecute(lua_State* L) { const char* query = Eluna::CHECKVAL(L, 1); + + int numArgs = lua_gettop(L); + if (numArgs > 1) + query = Eluna::FormatQuery(L, query).c_str(); + CharacterDatabase.Execute(query); return 0; } @@ -1440,6 +1458,10 @@ namespace LuaGlobalFunctions { const char* query = Eluna::CHECKVAL(L, 1); + int numArgs = lua_gettop(L); + if (numArgs > 1) + query = Eluna::FormatQuery(L, query).c_str(); + QueryResult result = LoginDatabase.Query(query); if (result) Eluna::Push(L, new QueryResult(result)); @@ -1481,6 +1503,11 @@ namespace LuaGlobalFunctions int AuthDBExecute(lua_State* L) { const char* query = Eluna::CHECKVAL(L, 1); + + int numArgs = lua_gettop(L); + if (numArgs > 1) + query = Eluna::FormatQuery(L, query).c_str(); + LoginDatabase.Execute(query); return 0; }