Lua rework almost done

This commit is contained in:
Fredy 2021-11-05 07:58:27 +01:00
parent 26833a556a
commit fd245cb2ac
12 changed files with 188 additions and 218 deletions

3
.gitignore vendored
View File

@ -10,4 +10,5 @@
.vscode
*.zip
cmake-build-debug
.idea
.idea
.vs

View File

@ -1,15 +1,15 @@
cmake_minimum_required(VERSION 3.13)
project(MySQLOO)
project(mysqloo)
add_subdirectory(GmodLUA)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
file(GLOB_RECURSE MySQLOO_SRC "src/*.h" "src/*.cpp")
set(SOURCE_FILES ${MySQLOO_SRC} src/Main.cpp)
file(GLOB_RECURSE MYSQLOO_SRC "src/*.h" "src/*.cpp")
set(SOURCE_FILES ${MYSQLOO_SRC} src/Main.cpp)
set(CMAKE_BUILD_TYPE Debug)
add_executable(MySQLOO ${SOURCE_FILES})
target_link_libraries(MySQLOO gmod-module-base)
add_library(mysqloo SHARED ${SOURCE_FILES})
target_link_libraries(mysqloo gmod-module-base)
target_include_directories(MySQLOO PRIVATE MySQL/include)
target_include_directories(mysqloo PRIVATE MySQL/include)
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
if (WIN32)
@ -30,11 +30,11 @@ elseif (CMAKE_SIZEOF_VOID_P EQUAL 4)
endif ()
if (WIN32)
target_link_libraries(MySQLOO ${MARIADB_CLIENT_LIB} crypt32 ws2_32 shlwapi bcrypt secur32)
target_link_libraries(mysqloo ${MARIADB_CLIENT_LIB} crypt32 ws2_32 shlwapi bcrypt secur32)
else ()
find_package(Threads REQUIRED)
target_link_libraries(MySQLOO ${MARIADB_CLIENT_LIB} ${SSL_LIB} ${CRYPTO_LIB} Threads::Threads ${CMAKE_DL_LIBS})
target_link_libraries(mysqloo ${MARIADB_CLIENT_LIB} ${SSL_LIB} ${CRYPTO_LIB} Threads::Threads ${CMAKE_DL_LIBS})
endif ()
set_gmod_suffix_prefix(MySQLOO)
set_gmod_suffix_prefix(mysqloo)

View File

@ -28,30 +28,6 @@ GMOD_MODULE_CLOSE() {
return 0;
}
/* Connects to the database and returns a Database instance that can be used
* as an interface to the mysql server.
*/
LUA_FUNCTION(mysqlooConnect) {
LUA->CheckType(1, GarrysMod::Lua::Type::String);
LUA->CheckType(2, GarrysMod::Lua::Type::String);
LUA->CheckType(3, GarrysMod::Lua::Type::String);
LUA->CheckType(4, GarrysMod::Lua::Type::String);
std::string host = LUA->GetString(1);
std::string username = LUA->GetString(2);
std::string pw = LUA->GetString(3);
std::string database = LUA->GetString(4);
unsigned int port = 3306;
std::string unixSocket;
if (LUA->IsType(5, GarrysMod::Lua::Type::Number)) {
port = (int)LUA->GetNumber(5);
}
if (LUA->IsType(6, GarrysMod::Lua::Type::String)) {
unixSocket = LUA->GetString(6);
}
auto object = Database::createDatabase(host, username, pw, database, port, unixSocket);
return 1;
}
/* Returns the amount of LuaObjectBase objects that are currently in use
* This includes Database and Query instances
*/
@ -91,13 +67,13 @@ static void printMessage(GarrysMod::Lua::ILuaBase* LUA, const char* str, int r,
LUA->ReferenceFree(ref);
}
static int printOutdatatedVersion(lua_State* state) {
static int printOutdatedVersion(lua_State* state) {
GarrysMod::Lua::ILuaBase* LUA = state->luabase;
LUA->SetState(state);
printMessage(LUA, "Your server is using an outdated mysqloo9 version\n", 255, 0, 0);
printMessage(LUA, "Download the latest version from here:\n", 255, 0, 0);
printMessage(LUA, "https://github.com/FredyH/MySQLOO/releases\n", 86, 156, 214);
runInTimer(LUA, 300, printOutdatatedVersion);
runInTimer(LUA, 300, printOutdatedVersion);
return 0;
}
@ -107,7 +83,7 @@ static int fetchSuccessful(lua_State* state) {
std::string version = LUA->GetString(1);
//version.size() < 3 so that the 404 response gets ignored
if (version != MYSQLOO_MINOR_VERSION && version.size() <= 3) {
printOutdatatedVersion(state);
printOutdatedVersion(state);
} else {
printMessage(LUA, "Your server is using the latest mysqloo9 version\n", 0, 255, 0);
}
@ -151,12 +127,18 @@ static int doVersionCheck(lua_State* state) {
return 0;
}
//TODO List:
// - memory leak with queries because sometimes first data is not cleared
// - onData callbacks
// - PreparedQueries do not properly clear their results
GMOD_MODULE_OPEN() {
if (mysql_library_init(0, nullptr, nullptr)) {
LUA->ThrowError("Could not initialize mysql library.");
}
//Creating MetaTables
LuaObject::createUserDataMetaTable(LUA);
LuaDatabase::createMetaTable(LUA);
LuaQuery::createMetaTable(LUA);
LuaPreparedQuery::createMetaTable(LUA);
@ -194,7 +176,7 @@ GMOD_MODULE_OPEN() {
LUA->PushNumber(OPTION_NAMED_FIELDS); LUA->SetField(-2, "OPTION_NAMED_FIELDS"); //Not used anymore
LUA->PushNumber(OPTION_CACHE); LUA->SetField(-2, "OPTION_CACHE"); //Not used anymore
LUA->PushCFunction(mysqlooConnect); LUA->SetField(-2, "connect");
LUA->PushCFunction(LuaDatabase::create); LUA->SetField(-2, "connect");
LUA->PushCFunction(objectCount); LUA->SetField(-2, "objectCount");
LUA->SetField(-2, "mysqloo");

View File

@ -6,7 +6,7 @@
static void pushLuaObjectTable(ILuaBase *LUA, void *data, int type) {
LUA->CreateTable();
LUA->PushUserType(data, type);
LUA->PushUserType(data, LuaObject::TYPE_USERDATA);
LUA->SetField(-2, "__CppObject");
LUA->PushMetaTable(type);
LUA->SetMetaTable(-2);
@ -37,7 +37,7 @@ LUA_CLASS_FUNCTION(LuaDatabase, create) {
}
MYSQLOO_LUA_FUNCTION(query) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
LUA->CheckType(2, GarrysMod::Lua::Type::String);
unsigned int outLen = 0;
const char *queryStr = LUA->GetString(2, &outLen);
@ -49,7 +49,7 @@ MYSQLOO_LUA_FUNCTION(query) {
}
MYSQLOO_LUA_FUNCTION(prepare) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
LUA->CheckType(2, GarrysMod::Lua::Type::String);
unsigned int outLen = 0;
const char *queryStr = LUA->GetString(2, &outLen);
@ -61,7 +61,7 @@ MYSQLOO_LUA_FUNCTION(prepare) {
}
MYSQLOO_LUA_FUNCTION(createTransaction) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
auto transaction = Transaction::create(database->m_database);
auto luaTransaction = LuaTransaction::create(transaction);
@ -70,7 +70,7 @@ MYSQLOO_LUA_FUNCTION(createTransaction) {
}
MYSQLOO_LUA_FUNCTION(connect) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
if (database->m_tableReference == 0) {
LUA->Push(1);
database->m_tableReference = LUA->ReferenceCreate();
@ -80,7 +80,7 @@ MYSQLOO_LUA_FUNCTION(connect) {
}
MYSQLOO_LUA_FUNCTION(escape) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
unsigned int nQueryLength;
const char *sQuery = LUA->GetString(2, &nQueryLength);
auto escaped = database->m_database->escape(std::string(sQuery, nQueryLength));
@ -89,7 +89,7 @@ MYSQLOO_LUA_FUNCTION(escape) {
}
MYSQLOO_LUA_FUNCTION(setCharacterSet) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
LUA->CheckType(2, GarrysMod::Lua::Type::String);
const char *charset = LUA->GetString(2);
bool success = database->m_database->setCharacterSet(charset);
@ -99,7 +99,7 @@ MYSQLOO_LUA_FUNCTION(setCharacterSet) {
}
MYSQLOO_LUA_FUNCTION(setSSLSettings) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
SSLSettings sslSettings;
if (LUA->IsType(2, GarrysMod::Lua::Type::String)) {
sslSettings.key = LUA->GetString(2);
@ -121,7 +121,7 @@ MYSQLOO_LUA_FUNCTION(setSSLSettings) {
}
MYSQLOO_LUA_FUNCTION(disconnect) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
bool wait = false;
if (LUA->IsType(2, GarrysMod::Lua::Type::Bool)) {
wait = LUA->GetBool(2);
@ -131,52 +131,52 @@ MYSQLOO_LUA_FUNCTION(disconnect) {
}
MYSQLOO_LUA_FUNCTION(status) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
LUA->PushNumber(database->m_database->m_status);
return 1;
}
MYSQLOO_LUA_FUNCTION(serverVersion) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
LUA->PushNumber(database->m_database->serverVersion());
return 1;
}
MYSQLOO_LUA_FUNCTION(serverInfo) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
LUA->PushString(database->m_database->serverInfo().c_str());
return 1;
}
MYSQLOO_LUA_FUNCTION(hostInfo) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
LUA->PushString(database->m_database->hostInfo().c_str());
return 1;
}
MYSQLOO_LUA_FUNCTION(setAutoReconnect) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
LUA->CheckType(2, GarrysMod::Lua::Type::Bool);
database->m_database->setAutoReconnect(LUA->GetBool(2));
return 0;
}
MYSQLOO_LUA_FUNCTION(setMultiStatements) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
LUA->CheckType(2, GarrysMod::Lua::Type::Bool);
database->m_database->setMultiStatements(LUA->GetBool(2));
return 0;
}
MYSQLOO_LUA_FUNCTION(setCachePreparedStatements) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
LUA->CheckType(2, GarrysMod::Lua::Type::Bool);
database->m_database->setCachePreparedStatements(LUA->GetBool(2));
return 0;
}
MYSQLOO_LUA_FUNCTION(abortAllQueries) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
auto abortedQueries = database->m_database->abortAllQueries();
for (auto pair: abortedQueries) {
//TODO:
@ -187,19 +187,19 @@ MYSQLOO_LUA_FUNCTION(abortAllQueries) {
}
MYSQLOO_LUA_FUNCTION(queueSize) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
LUA->PushNumber((double) database->m_database->queueSize());
return 1;
}
MYSQLOO_LUA_FUNCTION(ping) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
LUA->PushBool(database->m_database->ping());
return 1;
}
MYSQLOO_LUA_FUNCTION(wait) {
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA, LuaObject::TYPE_DATABASE);
auto database = LuaObject::getLuaObject<LuaDatabase>(LUA);
database->m_database->wait();
return 0;
}
@ -277,7 +277,7 @@ void LuaDatabase::think(ILuaBase *LUA) {
LUA->GetField(-1, "onConnected");
if (LUA->GetType(-1) == GarrysMod::Lua::Type::Function) {
LUA->ReferencePush(this->m_tableReference);
pcallWithErrorReporter(LUA, 1, 0);
pcallWithErrorReporter(LUA, 1);
}
LUA->Pop(); //Callback function
} else {
@ -286,7 +286,7 @@ void LuaDatabase::think(ILuaBase *LUA) {
LUA->ReferencePush(this->m_tableReference);
auto error = database->connectionError();
LUA->PushString(error.c_str());
pcallWithErrorReporter(LUA, 2, 0);
pcallWithErrorReporter(LUA, 2);
}
LUA->Pop(); //Callback function
}
@ -300,10 +300,9 @@ void LuaDatabase::think(ILuaBase *LUA) {
auto finishedQueries = database->takeFinishedQueries();
for (auto &pair: finishedQueries) {
auto data = pair.second;
auto query = pair.first;
if (data->m_tableReference != 0) {
LUA->ReferencePush(data->m_tableReference);
auto luaQuery = LuaIQuery::getLuaIQuery(LUA, -1);
auto luaQuery = LuaIQuery::getLuaObject<LuaIQuery>(LUA, -1);
LUA->Pop();
luaQuery->runCallback(LUA, data);
}

View File

@ -4,14 +4,14 @@
MYSQLOO_LUA_FUNCTION(start) {
auto query = LuaIQuery::getLuaIQuery(LUA);
auto queryData = query->buildQueryData(nullptr, 0);
auto query = LuaIQuery::getLuaObject<LuaIQuery>(LUA);
auto queryData = query->buildQueryData(LUA, 1);
query->m_query->start(queryData);
return 0;
}
MYSQLOO_LUA_FUNCTION(error) {
auto query = LuaIQuery::getLuaIQuery(LUA);
auto query = LuaIQuery::getLuaObject<LuaIQuery>(LUA);
LUA->PushString(query->m_query->error().c_str());
return 1;
}
@ -21,13 +21,13 @@ MYSQLOO_LUA_FUNCTION(wait) {
if (LUA->IsType(2, GarrysMod::Lua::Type::Bool)) {
shouldSwap = LUA->GetBool(2);
}
auto query = LuaIQuery::getLuaIQuery(LUA);
auto query = LuaIQuery::getLuaObject<LuaIQuery>(LUA);
query->m_query->wait(shouldSwap);
return 0;
}
MYSQLOO_LUA_FUNCTION(setOption) {
auto query = LuaIQuery::getLuaIQuery(LUA);
auto query = LuaIQuery::getLuaObject<LuaIQuery>(LUA);
LUA->CheckType(2, GarrysMod::Lua::Type::Number);
bool set = true;
int option = (int) LUA->GetNumber(2);
@ -41,13 +41,13 @@ MYSQLOO_LUA_FUNCTION(setOption) {
}
MYSQLOO_LUA_FUNCTION(isRunning) {
auto query = LuaIQuery::getLuaIQuery(LUA);
auto query = LuaIQuery::getLuaObject<LuaIQuery>(LUA);
LUA->PushBool(query->m_query->isRunning());
return 1;
}
MYSQLOO_LUA_FUNCTION(abort) {
auto query = LuaIQuery::getLuaIQuery(LUA);
auto query = LuaIQuery::getLuaObject<LuaIQuery>(LUA);
auto abortedData = query->m_query->abort();
for (auto &data: abortedData) {
LuaIQuery::runAbortedCallback(LUA, data);
@ -58,25 +58,25 @@ MYSQLOO_LUA_FUNCTION(abort) {
void LuaIQuery::runAbortedCallback(ILuaBase *LUA, const std::shared_ptr<IQueryData> &data) {
if (data->m_tableReference == 0) return;
if (!LuaIQuery::getCallbackReference(LUA, data->m_abortReference, data->m_tableReference,
"onAborted", data->isFirstData())) {
if (!LuaIQuery::pushCallbackReference(LUA, data->m_abortReference, data->m_tableReference,
"onAborted", data->isFirstData())) {
return;
}
LUA->ReferencePush(data->m_tableReference);
LuaObject::pcallWithErrorReporter(LUA, 1, 0);
LuaObject::pcallWithErrorReporter(LUA, 1);
}
void LuaIQuery::runErrorCallback(ILuaBase *LUA, const std::shared_ptr<IQueryData> &data) {
if (data->m_tableReference == 0) return;
if (!LuaIQuery::getCallbackReference(LUA, data->m_errorReference, data->m_tableReference,
"onError", data->isFirstData())) {
if (!LuaIQuery::pushCallbackReference(LUA, data->m_errorReference, data->m_tableReference,
"onError", data->isFirstData())) {
return;
}
LUA->ReferencePush(data->m_tableReference);
auto error = data->getError();
LUA->PushString(error.c_str());
LuaObject::pcallWithErrorReporter(LUA, 2, 0);
LuaObject::pcallWithErrorReporter(LUA, 2);
}
void LuaIQuery::addMetaTableFunctions(ILuaBase *LUA) {

View File

@ -31,19 +31,6 @@ public:
void finishQueryData(ILuaBase *LUA, const std::shared_ptr<IQueryData>& data) const;
static LuaIQuery *getLuaIQuery(ILuaBase *LUA, int stackPos = 1) {
int type = LuaObject::getLuaObjectType(LUA, stackPos);
if (type != LuaObject::TYPE_QUERY && type != LuaObject::TYPE_PREPARED_QUERY &&
type != LuaObject::TYPE_TRANSACTION) {
LUA->ThrowError("[MySQLOO] Expected MySQLOO table");
}
auto *returnValue = LuaObject::getLuaObject<LuaIQuery>(LUA, type, stackPos);
if (returnValue == nullptr) {
LUA->ThrowError("[MySQLOO] Expected MySQLOO table");
}
return returnValue;
}
protected:
explicit LuaIQuery(std::shared_ptr<IQuery> query, std::string className) : LuaObject(std::move(className)),
m_query(std::move(query)) {}

View File

@ -1,7 +1,9 @@
#include <algorithm>
#include "LuaObject.h"
#include "LuaDatabase.h"
#include <iostream>
int LuaObject::TYPE_USERDATA = 0;
int LuaObject::TYPE_DATABASE = 0;
int LuaObject::TYPE_QUERY = 0;
int LuaObject::TYPE_TRANSACTION = 0;
@ -10,29 +12,14 @@ int LuaObject::TYPE_PREPARED_QUERY = 0;
std::deque<std::shared_ptr<LuaObject>> LuaObject::luaObjects = {};
std::deque<std::shared_ptr<LuaDatabase>> LuaObject::luaDatabases = {};
std::string LuaObject::toString() {
std::stringstream ss;
ss << s_className << " " << this;
return ss.str();
}
std::shared_ptr<LuaObject> LuaObject::checkMySQLOOType(ILuaBase *lua, int position) {
int type = lua->GetType(position);
if (type != LuaObject::TYPE_DATABASE && type != LuaObject::TYPE_PREPARED_QUERY &&
type != LuaObject::TYPE_QUERY && type != LuaObject::TYPE_TRANSACTION) {
lua->ThrowError("Provided argument is not a valid MySQLOO object");
}
return lua->GetUserType<LuaObject>(position, type)->shared_from_this();
}
LUA_FUNCTION(luaObjectGc) {
auto luaObject = LuaObject::checkMySQLOOType(LUA);
auto luaObject = LUA->GetUserType<LuaObject>(1, LuaObject::TYPE_USERDATA);
LuaObject::luaDatabases.erase(
std::remove(LuaObject::luaDatabases.begin(), LuaObject::luaDatabases.end(), luaObject),
std::remove(LuaObject::luaDatabases.begin(), LuaObject::luaDatabases.end(), luaObject->shared_from_this()),
LuaObject::luaDatabases.end()
);
LuaObject::luaObjects.erase(
std::remove(LuaObject::luaObjects.begin(), LuaObject::luaObjects.end(), luaObject),
std::remove(LuaObject::luaObjects.begin(), LuaObject::luaObjects.end(), luaObject->shared_from_this()),
LuaObject::luaObjects.end()
);
//After this function this object should be deleted.
@ -41,13 +28,6 @@ LUA_FUNCTION(luaObjectGc) {
return 0;
}
LUA_FUNCTION(luaObjectToString) {
auto luaObject = LuaObject::checkMySQLOOType(LUA);
auto str = luaObject->toString();
LUA->PushString(str.c_str());
return 1;
}
LUA_CLASS_FUNCTION(LuaObject, luaObjectThink) {
std::deque<std::shared_ptr<LuaDatabase>> databasesCopy = LuaObject::luaDatabases;
for (auto &database: databasesCopy) {
@ -56,16 +36,33 @@ LUA_CLASS_FUNCTION(LuaObject, luaObjectThink) {
return 0;
}
void LuaObject::createUserDataMetaTable(GarrysMod::Lua::ILuaBase *LUA) {
TYPE_USERDATA = LUA->CreateMetaTable("MySQLOO UserData");
LUA->PushCFunction(luaObjectGc);
LUA->SetField(-2, "__gc");
LUA->Pop();
}
void LuaObject::addMetaTableFunctions(GarrysMod::Lua::ILuaBase *lua) {
lua->Push(-1);
lua->SetField(-2, "__index");
std::string LuaObject::toString() {
std::stringstream ss;
ss << m_className << " " << this;
return ss.str();
}
lua->PushCFunction(luaObjectGc);
lua->SetField(-2, "__gc");
LUA_FUNCTION(luaObjectToString) {
LUA->GetUserType<LuaObject>(1, LuaObject::TYPE_USERDATA);
auto luaObject = LuaObject::getLuaObject<LuaObject>(LUA);
auto str = luaObject->toString();
LUA->PushString(str.c_str());
return 1;
}
lua->PushCFunction(luaObjectToString);
lua->SetField(-2, "__tostring");
void LuaObject::addMetaTableFunctions(GarrysMod::Lua::ILuaBase *LUA) {
LUA->Push(-1);
LUA->SetField(-2, "__index");
LUA->PushCFunction(luaObjectToString);
LUA->SetField(-2, "__tostring");
}
LUA_FUNCTION(errorReporter) {
@ -75,31 +72,42 @@ LUA_FUNCTION(errorReporter) {
if (LUA->IsType(-1, GarrysMod::Lua::Type::Function)) {
LUA->Push(1);
LUA->Call(1, 1);
LUA->Call(1, 1); //The resulting stack trace will be returned
} else {
LUA->Pop(3); // global, traceback
LUA->PushString("MySQLOO Error");
}
return 1;
}
void LuaObject::pcallWithErrorReporter(ILuaBase *LUA, int nargs, int nresults) {
void LuaObject::pcallWithErrorReporter(ILuaBase *LUA, int nargs) {
LUA->PushCFunction(errorReporter);
int errorHandlerIndex = LUA->Top() - nargs - 2;
LUA->Insert(-nargs - 2);
LUA->PCall(nargs, nresults, errorHandlerIndex);
int errorHandlerIndex = LUA->Top() - nargs - 1;
LUA->Insert(errorHandlerIndex);
int pcallResult = LUA->PCall(nargs, 0, errorHandlerIndex);
if (pcallResult == 2) { //LUA_ERRRUN, we now have a stack trace on the stack
LUA->PushSpecial(GarrysMod::Lua::SPECIAL_GLOB);
LUA->GetField(-1, "ErrorNoHalt");
if (LUA->IsType(-1, GarrysMod::Lua::Type::Function)) {
LUA->Push(-3); //Stack trace
LUA->Call(1, 0);
LUA->Pop(2); //Stack trace, global
} else {
LUA->Pop(3); //Stack trace, global, nil
}
}
LUA->Pop(); //Error reporter
}
bool LuaObject::getCallbackReference(ILuaBase *LUA, int functionReference, int tableReference,
const std::string &callbackName, bool allowCallback) {
bool LuaObject::pushCallbackReference(ILuaBase *LUA, int functionReference, int tableReference,
const std::string &callbackName, bool allowCallback) {
//Push function reference
if (functionReference != 0) {
LUA->ReferencePush(functionReference);
return true;
} else if (allowCallback && tableReference != 0) {
LUA->ReferencePush(tableReference);
LUA->GetField(-1, callbackName.c_str());
LUA->Remove(-2);
LUA->Remove(LUA->Top() - 2);
if (LUA->IsType(-1, GarrysMod::Lua::Type::Function)) {
return true;
} else {
@ -109,7 +117,6 @@ bool LuaObject::getCallbackReference(ILuaBase *LUA, int functionReference, int t
} else {
return false;
}
return true;
}

View File

@ -10,67 +10,67 @@
#include "GarrysMod/Lua/Interface.h"
#include "../mysql/MySQLOOException.h"
#include <iostream>
class LuaDatabase;
using namespace GarrysMod::Lua;
class LuaObject : public std::enable_shared_from_this<LuaObject> {
public:
virtual ~LuaObject() = default;
std::string toString();
static std::deque<std::shared_ptr<LuaObject>> luaObjects;
static std::deque<std::shared_ptr<LuaDatabase>> luaDatabases;
static std::shared_ptr<LuaObject> checkMySQLOOType(ILuaBase *lua, int position = 1);
static int TYPE_USERDATA;
static int TYPE_DATABASE;
static int TYPE_QUERY;
static int TYPE_PREPARED_QUERY;
static int TYPE_TRANSACTION;
static void addMetaTableFunctions(ILuaBase *lua);
static void addMetaTableFunctions(ILuaBase *LUA);
static void createUserDataMetaTable(ILuaBase *lua);
//Lua functions
static int luaObjectThink(lua_State *L);
static void pcallWithErrorReporter(ILuaBase *LUA, int nargs, int nresults);
static void pcallWithErrorReporter(ILuaBase *LUA, int nargs);
static bool getCallbackReference(ILuaBase *LUA, int functionReference, int tableReference,
const std::string &callbackName, bool allowCallback);
static bool pushCallbackReference(ILuaBase *LUA, int functionReference, int tableReference,
const std::string &callbackName, bool allowCallback);
static int getLuaObjectType(ILuaBase *LUA, int stackPos = 1) {
LUA->CheckType(stackPos, GarrysMod::Lua::Type::Table);
LUA->GetField(stackPos, "__CppObject");
int type = LUA->GetType(-1);
LUA->Pop();
return type;
}
template<typename T>
static T *getLuaObject(ILuaBase *LUA, int type, int stackPos = 1) {
template<class T>
static T *getLuaObject(ILuaBase *LUA, int stackPos = 1) {
LUA->CheckType(stackPos, GarrysMod::Lua::Type::Table);
LUA->GetField(stackPos, "__CppObject");
T *returnValue = LUA->GetUserType<T>(-1, type);
if (returnValue == nullptr) {
auto *luaObject = LUA->GetUserType<LuaObject>(-1, TYPE_USERDATA);
if (luaObject == nullptr) {
LUA->ThrowError("[MySQLOO] Expected MySQLOO table");
}
T *returnValue = dynamic_cast<T*>(luaObject);
if (returnValue == nullptr) {
LUA->ThrowError("[MySQLOO] Invalid CPP Object");
}
LUA->Pop();
return returnValue;
}
static int getFunctionReference(ILuaBase *LUA, int stackPosition, const char* fieldName);
static int getFunctionReference(ILuaBase *LUA, int stackPosition, const char *fieldName);
protected:
explicit LuaObject(std::string className) : s_className(std::move(className)) {
explicit LuaObject(std::string className) : m_className(std::move(className)) {
}
std::string s_className;
std::string m_className;
};
#define MYSQLOO_LUA_FUNCTION(FUNC) \
static int FUNC##__Imp( GarrysMod::Lua::ILuaBase* LUA ); \
static int FUNC( lua_State* L ) \

View File

@ -1,8 +1,7 @@
#include "LuaPreparedQuery.h"
#include "../mysql/PreparedQuery.h"
MYSQLOO_LUA_FUNCTION(setNumber) {
auto luaQuery = LuaObject::getLuaObject<LuaPreparedQuery>(LUA, LuaObject::TYPE_PREPARED_QUERY);
auto luaQuery = LuaObject::getLuaObject<LuaPreparedQuery>(LUA);
auto query = (PreparedQuery *) luaQuery->m_query.get();
LUA->CheckType(2, GarrysMod::Lua::Type::Number);
LUA->CheckType(3, GarrysMod::Lua::Type::Number);
@ -15,7 +14,7 @@ MYSQLOO_LUA_FUNCTION(setNumber) {
}
MYSQLOO_LUA_FUNCTION(setString) {
auto luaQuery = LuaObject::getLuaObject<LuaPreparedQuery>(LUA, LuaObject::TYPE_PREPARED_QUERY);
auto luaQuery = LuaObject::getLuaObject<LuaPreparedQuery>(LUA);
auto query = (PreparedQuery *) luaQuery->m_query.get();
LUA->CheckType(2, GarrysMod::Lua::Type::Number);
LUA->CheckType(3, GarrysMod::Lua::Type::String);
@ -28,7 +27,7 @@ MYSQLOO_LUA_FUNCTION(setString) {
}
MYSQLOO_LUA_FUNCTION(setBoolean) {
auto luaQuery = LuaObject::getLuaObject<LuaPreparedQuery>(LUA, LuaObject::TYPE_PREPARED_QUERY);
auto luaQuery = LuaObject::getLuaObject<LuaPreparedQuery>(LUA);
auto query = (PreparedQuery *) luaQuery->m_query.get();
LUA->CheckType(2, GarrysMod::Lua::Type::Number);
LUA->CheckType(3, GarrysMod::Lua::Type::Bool);
@ -40,7 +39,7 @@ MYSQLOO_LUA_FUNCTION(setBoolean) {
}
MYSQLOO_LUA_FUNCTION(setNull) {
auto luaQuery = LuaObject::getLuaObject<LuaPreparedQuery>(LUA, LuaObject::TYPE_PREPARED_QUERY);
auto luaQuery = LuaObject::getLuaObject<LuaPreparedQuery>(LUA);
auto query = (PreparedQuery *) luaQuery->m_query.get();
LUA->CheckType(2, GarrysMod::Lua::Type::Number);
double index = LUA->GetNumber(2);
@ -50,14 +49,14 @@ MYSQLOO_LUA_FUNCTION(setNull) {
}
MYSQLOO_LUA_FUNCTION(putNewParameters) {
auto luaQuery = LuaObject::getLuaObject<LuaPreparedQuery>(LUA, LuaObject::TYPE_PREPARED_QUERY);
auto luaQuery = LuaObject::getLuaObject<LuaPreparedQuery>(LUA);
auto query = (PreparedQuery *) luaQuery->m_query.get();
query->putNewParameters();
return 0;
}
MYSQLOO_LUA_FUNCTION(clearParameters) {
auto luaQuery = LuaObject::getLuaObject<LuaPreparedQuery>(LUA, LuaObject::TYPE_PREPARED_QUERY);
auto luaQuery = LuaObject::getLuaObject<LuaPreparedQuery>(LUA);
auto query = (PreparedQuery *) luaQuery->m_query.get();
query->clearParameters();
return 0;

View File

@ -39,7 +39,6 @@ static void dataToLua(Query &query,
} else {
LUA->SetField(-2, columnName);
}
LUA->Pop();
}
//Stores the data associated with the current result set of the query
@ -74,33 +73,33 @@ int LuaQuery::createDataReference(GarrysMod::Lua::ILuaBase *LUA, Query &query, Q
void LuaQuery::runSuccessCallback(ILuaBase *LUA, const std::shared_ptr<IQueryData> &data) {
auto query = std::dynamic_pointer_cast<Query>(m_query);
auto queryData = std::dynamic_pointer_cast<QueryData>(data);
int tableReference = LuaQuery::createDataReference(LUA, *query, *queryData);
int dataReference = LuaQuery::createDataReference(LUA, *query, *queryData);
if (!LuaIQuery::getCallbackReference(LUA, data->m_successReference, data->m_tableReference,
"onSuccess", data->isFirstData())) {
if (!LuaIQuery::pushCallbackReference(LUA, data->m_successReference, data->m_tableReference,
"onSuccess", data->isFirstData())) {
return;
}
LUA->ReferencePush(data->m_tableReference);
LUA->ReferencePush(tableReference);
LuaObject::pcallWithErrorReporter(LUA, 2, 0);
LUA->ReferencePush(dataReference);
LuaObject::pcallWithErrorReporter(LUA, 2);
}
MYSQLOO_LUA_FUNCTION(affectedRows) {
auto luaQuery = LuaQuery::getLuaQuery(LUA);
auto luaQuery = LuaQuery::getLuaObject<LuaQuery>(LUA);
auto query = (Query *) luaQuery->m_query.get();
LUA->PushNumber((double) query->affectedRows());
return 1;
}
MYSQLOO_LUA_FUNCTION(lastInsert) {
auto luaQuery = LuaQuery::getLuaQuery(LUA);
auto luaQuery = LuaQuery::getLuaObject<LuaQuery>(LUA);
auto query = (Query *) luaQuery->m_query.get();
LUA->PushNumber((double) query->lastInsert());
return 1;
}
MYSQLOO_LUA_FUNCTION(getData) {
auto luaQuery = LuaQuery::getLuaQuery(LUA);
auto luaQuery = LuaQuery::getLuaObject<LuaQuery>(LUA);
auto query = (Query *) luaQuery->m_query.get();
if (!query->hasCallbackData() || query->callbackQueryData->getResultStatus() == QUERY_ERROR) {
LUA->PushNil();
@ -112,14 +111,14 @@ MYSQLOO_LUA_FUNCTION(getData) {
}
MYSQLOO_LUA_FUNCTION(hasMoreResults) {
auto luaQuery = LuaQuery::getLuaQuery(LUA);
auto luaQuery = LuaQuery::getLuaObject<LuaQuery>(LUA);
auto query = (Query *) luaQuery->m_query.get();
LUA->PushBool(query->hasMoreResults());
return 1;
}
LUA_FUNCTION(getNextResults) {
auto luaQuery = LuaQuery::getLuaQuery(LUA);
auto luaQuery = LuaQuery::getLuaObject<LuaQuery>(LUA);
auto query = (Query *) luaQuery->m_query.get();
query->getNextResults();
return 0;

View File

@ -15,18 +15,6 @@ public:
static void createMetaTable(ILuaBase *LUA);
static LuaQuery *getLuaQuery(ILuaBase *LUA, int stackPos = 1) {
int type = LuaObject::getLuaObjectType(LUA, stackPos);
if (type != LuaObject::TYPE_QUERY && type != LuaObject::TYPE_PREPARED_QUERY) {
LUA->ThrowError("[MySQLOO] Expected MySQLOO query");
}
auto *returnValue = LuaObject::getLuaObject<LuaQuery>(LUA, type, stackPos);
if (returnValue == nullptr) {
LUA->ThrowError("[MySQLOO] Expected MySQLOO table");
}
return returnValue;
}
static std::shared_ptr<LuaQuery> create(const std::shared_ptr<Query> &query) {
auto instance = std::shared_ptr<LuaQuery>(new LuaQuery(query, "MySQLOO Query"));
LuaObject::luaObjects.push_back(instance);

View File

@ -3,10 +3,9 @@
#include "../mysql/Transaction.h"
MYSQLOO_LUA_FUNCTION(addQuery) {
auto luaTransaction = LuaObject::getLuaObject<LuaTransaction>(LUA, LuaObject::TYPE_TRANSACTION);
auto luaTransaction = LuaObject::getLuaObject<LuaTransaction>(LUA);
auto addedLuaQuery = LuaQuery::getLuaQuery(LUA, 2);
auto addedQuery = (Query *) addedLuaQuery->m_query.get();
auto addedLuaQuery = LuaQuery::getLuaObject<LuaQuery>(LUA, 2);
LUA->Push(1);
LUA->GetField(-1, "__queries");
if (LUA->IsType(-1, GarrysMod::Lua::Type::Nil)) {
@ -36,7 +35,7 @@ MYSQLOO_LUA_FUNCTION(getQueries) {
}
MYSQLOO_LUA_FUNCTION(clearQueries) {
auto luaTransaction = LuaObject::getLuaObject<LuaTransaction>(LUA, LuaObject::TYPE_TRANSACTION);
auto luaTransaction = LuaObject::getLuaObject<LuaTransaction>(LUA);
LUA->Push(1);
LUA->CreateTable();
@ -63,23 +62,24 @@ void LuaTransaction::createMetaTable(ILuaBase *LUA) {
std::shared_ptr<IQueryData> LuaTransaction::buildQueryData(ILuaBase *LUA, int stackPosition) {
LUA->GetField(stackPosition, "__queries");
std::deque<std::pair<std::shared_ptr<Query>, std::shared_ptr<IQueryData>>> queries;
for (int i = 0; i < this->m_addedQueryData.size(); i++) {
auto& queryData = this->m_addedQueryData[i];
LUA->PushNumber((double) (i + 1));
LUA->RawGet(-2);
if (!LUA->IsType(-1, GarrysMod::Lua::Type::Table)) {
LUA->Pop();
break;
if (LUA->GetType(-1) != GarrysMod::Lua::Type::Nil) {
for (int i = 0; i < this->m_addedQueryData.size(); i++) {
auto &queryData = this->m_addedQueryData[i];
LUA->PushNumber((double) (i + 1));
LUA->RawGet(-2);
if (!LUA->IsType(-1, GarrysMod::Lua::Type::Table)) {
LUA->Pop(); //Nil or whatever else is on the stack
break;
}
auto luaQuery = LuaQuery::getLuaObject<LuaQuery>(LUA, -1);
auto query = std::dynamic_pointer_cast<Query>(luaQuery->m_query);
query->addQueryData(queryData);
queries.emplace_back(query, queryData);
LUA->Pop(); //Query
}
auto luaQuery = LuaQuery::getLuaQuery(LUA, -1);
auto query = std::dynamic_pointer_cast<Query>(luaQuery->m_query);
query->addQueryData(queryData);
queries.emplace_back(query, queryData);
}
LUA->Pop(); //Queries table
auto data = Transaction::buildQueryData(queries);
LuaIQuery::referenceCallbacks(LUA, stackPosition, *data);
return data;
@ -87,29 +87,37 @@ std::shared_ptr<IQueryData> LuaTransaction::buildQueryData(ILuaBase *LUA, int st
void LuaTransaction::runSuccessCallback(ILuaBase *LUA, const std::shared_ptr<IQueryData> &data) {
auto transactionData = std::dynamic_pointer_cast<TransactionData>(data);
if (transactionData->m_tableReference == 0) return;
transactionData->setStatus(QUERY_COMPLETE);
std::vector<int> queryTableRefs;
for (auto& pair : transactionData->m_queries) {
LUA->CreateTable();
int index = 0;
for (auto &pair: transactionData->m_queries) {
LUA->PushNumber((double) (++index));
auto query = pair.first;
//So we get the current data rather than caching it, if the same query is added multiple times.
query->m_dataReference = 0;
if (query->m_dataReference != 0) {
query->m_dataReference = 0;
LUA->ReferenceFree(query->m_dataReference);
}
auto queryData = std::dynamic_pointer_cast<QueryData>(pair.second);
query->setCallbackData(pair.second);
int ref = LuaQuery::createDataReference(LUA, *query, *queryData);
queryTableRefs.push_back(ref);
}
LUA->CreateTable();
for (size_t i = 0; i < queryTableRefs.size(); i++) {
LUA->PushNumber((double) (i + 1));
LUA->ReferencePush(queryTableRefs[i]);
LUA->ReferencePush(ref);
LUA->SetTable(-3);
//The last data reference can stay cached in the query and will be free'd once the query is gc'ed
}
int dataRef = LUA->ReferenceCreate();
if (data->getSuccessReference() != 0) {
} else if (data->isFirstData()) {
if (!LuaIQuery::pushCallbackReference(LUA, data->m_successReference, data->m_tableReference,
"onSuccess", data->isFirstData())) {
LUA->Pop(); //Table of results
return;
}
LUA->ReferencePush(transactionData->m_tableReference);
LUA->Push(-3); //Table of results
LuaObject::pcallWithErrorReporter(LUA, 2);
LUA->ReferenceFree(dataRef);
LUA->Pop(); //Table of results
for (auto &pair: transactionData->m_queries) {
LuaIQuery::finishQueryData(LUA, pair.second);
}
}