Skip to content

Commit c0dd54c

Browse files
committed
reconnection on sqlprep exec & prepare
1 parent 7b9491d commit c0dd54c

File tree

7 files changed

+180
-86
lines changed

7 files changed

+180
-86
lines changed

src/plugins/database/dbplugin.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ int DBPlugin::GetInt(char* sFunction, char* sParam1, int nParam2)
122122
int col = (nParam2 >> 24) & 0xFF;
123123
int stmtID = nParam2 & 0x00FFFFFF;
124124
return PrepGetDataInt(stmtID, col);
125+
} else if (function == "CON") {
126+
return Connect();
127+
} else if (function == "DISCON") {
128+
Disconnect();
129+
return 0;
125130
} else {
126131
logger->Err("! Unknown GetInt function '%s'", sFunction);
127132
return -1;
@@ -223,6 +228,9 @@ char* DBPlugin::GetString(char* sFunction, char* sParam1, int nParam2)
223228
return this->returnBuffer;
224229
}
225230

231+
bool DBPlugin::Connect() { return TRUE; }
232+
void DBPlugin::Disconnect() { }
233+
226234
bool DBPlugin::Execute(char* query)
227235
{
228236
logger->Err("* %s not implemented for this plugin", __FUNCTION__);

src/plugins/database/dbplugin.h

+3
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ class DBPlugin : public Plugin {
6363
virtual int GetLastInsertID();
6464
void SetScorcoSQL(const char* request);
6565

66+
virtual bool Connect();
67+
virtual void Disconnect();
68+
6669
// Prepared statements
6770
virtual int PrepPrepareStatement(const char* query);
6871

src/plugins/database/nwnx_sql.nss

-69
Original file line numberDiff line numberDiff line change
@@ -489,27 +489,6 @@ void SetPersistentString(object oObject, string sVarName, string sValue, int iEx
489489
+ sPlayer + "','" + sTag + "','" + sVarName + "','" + sValue + "'," + IntToString(iExpiration) + ")"
490490
+ " ON DUPLICATE KEY UPDATE `val`=VALUES(`val`), `expire`=VALUES(`expire`)"
491491
);
492-
493-
// string sSQL = "SELECT player FROM " + sTable + " WHERE player='" + sPlayer +
494-
// "' AND tag='" + sTag + "' AND name='" + sVarName + "'";
495-
// SQLExecDirect(sSQL);
496-
497-
// if (SQLFetch() == SQL_SUCCESS)
498-
// {
499-
// // row exists
500-
// sSQL = "UPDATE " + sTable + " SET val='" + sValue +
501-
// "',expire=" + IntToString(iExpiration) + " WHERE player='" + sPlayer +
502-
// "' AND tag='" + sTag + "' AND name='" + sVarName + "'";
503-
// SQLExecDirect(sSQL);
504-
// }
505-
// else
506-
// {
507-
// // row doesn't exist
508-
// sSQL = "INSERT INTO " + sTable + " (player,tag,name,val,expire) VALUES" +
509-
// "('" + sPlayer + "','" + sTag + "','" + sVarName + "','" +
510-
// sValue + "'," + IntToString(iExpiration) + ")";
511-
// SQLExecDirect(sSQL);
512-
// }
513492
}
514493

515494
}
@@ -582,30 +561,6 @@ void SetPersistentInt(object oObject, string sVarName, int iValue, int iExpirati
582561
int GetPersistentInt(object oObject, string sVarName, string sTable = "pwdata")
583562
{
584563
return StringToInt(GetPersistentString(oObject, sVarName, sTable));
585-
// string sPlayer;
586-
// string sTag;
587-
588-
// if (GetIsPC(oObject))
589-
// {
590-
// sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oObject));
591-
// sTag = SQLEncodeSpecialChars(GetName(oObject));
592-
// }
593-
// else
594-
// {
595-
// sPlayer = "~";
596-
// sTag = GetTag(oObject);
597-
// }
598-
599-
// sVarName = SQLEncodeSpecialChars(sVarName);
600-
601-
// string sSQL = "SELECT val FROM " + sTable + " WHERE player='" + sPlayer +
602-
// "' AND tag='" + sTag + "' AND name='" + sVarName + "'";
603-
// SQLExecDirect(sSQL);
604-
605-
// if (SQLFetch() == SQL_SUCCESS)
606-
// return StringToInt(SQLGetData(1));
607-
// else
608-
// return 0;
609564
}
610565

611566
void SetPersistentFloat(object oObject, string sVarName, float fValue, int iExpiration =
@@ -617,30 +572,6 @@ void SetPersistentFloat(object oObject, string sVarName, float fValue, int iExpi
617572
float GetPersistentFloat(object oObject, string sVarName, string sTable = "pwdata")
618573
{
619574
return StringToFloat(GetPersistentString(oObject, sVarName, sTable));
620-
// string sPlayer;
621-
// string sTag;
622-
623-
// if (GetIsPC(oObject))
624-
// {
625-
// sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oObject));
626-
// sTag = SQLEncodeSpecialChars(GetName(oObject));
627-
// }
628-
// else
629-
// {
630-
// sPlayer = "~";
631-
// sTag = GetTag(oObject);
632-
// }
633-
634-
// sVarName = SQLEncodeSpecialChars(sVarName);
635-
636-
// string sSQL = "SELECT val FROM " + sTable + " WHERE player='" + sPlayer +
637-
// "' AND tag='" + sTag + "' AND name='" + sVarName + "'";
638-
// SQLExecDirect(sSQL);
639-
640-
// if (SQLFetch() == SQL_SUCCESS)
641-
// return StringToFloat(SQLGetData(1));
642-
// else
643-
// return 0.0f;
644575
}
645576

646577
void SetPersistentLocation(object oObject, string sVarName, location lLocation, int iExpiration =

src/plugins/xp_mysql/mysql_plugin.cpp

+43-7
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "mysql_plugin.h"
2121

22+
#include "../../nwnx_version.h"
2223
#include <cassert>
2324
#include <mysql/errmsg.h>
2425

@@ -53,17 +54,17 @@ bool APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
5354
MySQL::MySQL()
5455
: DBPlugin()
5556
{
56-
header = "NWNX MySQL Plugin V.1.1.0-dev\n"
57+
header = "NWNX MySQL Plugin " NWNX_VERSION_INFO "\n"
5758
"(c) 2007 by Ingmar Stieger (Papillon)\n"
5859
"(c) 2008 by virusman\n"
59-
"visit us at http://www.nwnx.org\n"
60-
"(built using mysql-5.0.27 source)\n";
60+
"Source: https://github.com/nwn2dev/nwnx4 \n"
61+
"MySQL Connector: " MARIADB_CLIENT_VERSION_STR;
6162

6263
description = "This plugin provides database storage. It uses "
6364
"MySQL 4 or 5 as database server.";
6465

6566
subClass = "MySQL";
66-
version = "1.1.0-dev";
67+
version = NWNX_VERSION_INFO;
6768

6869
result = NULL;
6970
row = NULL;
@@ -106,15 +107,19 @@ bool MySQL::Init(char* nwnxhome)
106107

107108
bool MySQL::Connect()
108109
{
110+
logger->Info("* Connecting to MySQL server...");
109111
// initialize the mysql structure
110-
if (!mysql_init(&mysql))
111-
return FALSE;
112+
if (!mysql_init(&mysql)) {
113+
logger->Err("! Failed to init MySQL");
114+
return false;
115+
}
112116

113117
// try to connect to the mysql server
114118
connection = mysql_real_connect(&mysql, server.c_str(), user.c_str(), password.c_str(),
115119
schema.c_str(), port, NULL, CLIENT_MULTI_STATEMENTS);
116120
if (connection == NULL) {
117121
mysql_close(&mysql);
122+
logger->Err("! Failed to connect to server: %s", mysql_error(&mysql));
118123
return false;
119124
}
120125

@@ -126,21 +131,38 @@ bool MySQL::Connect()
126131
}
127132
}
128133

134+
// Recover prepared statements
135+
for (size_t stmtID = 0; stmtID < m_prepStmts.size(); stmtID++) {
136+
auto& prepStmt = m_prepStmts[stmtID];
137+
138+
auto stmt = mysql_stmt_init(&mysql);
139+
if (mysql_stmt_prepare(stmt, prepStmt->query.c_str(), -1) != 0) {
140+
logger->Err("[Stmt %d] Failed to prepare statement. Error %d: %s", stmtID,
141+
mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
142+
mysql_stmt_close(stmt); // ignore closing error, just deallocate
143+
} else {
144+
logger->Debug("[Stmt %d] re-prepared statement after disconnection", stmtID);
145+
prepStmt->stmt = stmt;
146+
}
147+
}
148+
129149
return true;
130150
}
131151

132152
void MySQL::Disconnect()
133153
{
134154
// close the connection
135155
mysql_close(&mysql);
156+
mysql_close(connection);
157+
connection = NULL;
158+
logger->Info("* Disconnected MySQL server");
136159
}
137160

138161
bool MySQL::Reconnect()
139162
{
140163
logger->Info("* Reconnecting to MySQL server...");
141164
Disconnect();
142165
if (!Connect()) {
143-
logger->Info("* Connection to MySQL server failed:\n %s", mysql_error(&mysql));
144166
return false;
145167
} else {
146168
logger->Info("* Connection to MySQL server succeeded.");
@@ -421,6 +443,13 @@ BYTE* MySQL::ReadScorcoData(char* param, int* size)
421443

422444
int MySQL::PrepPrepareStatement(const char* query)
423445
{
446+
if (!connection) {
447+
if (!Reconnect()) {
448+
logger->Err("PrepPrepareStatement: Not connected.");
449+
return FALSE;
450+
}
451+
}
452+
424453
auto stmtID = m_prepStmts.size() + 1;
425454
logger->Info("[Stmt %d] Prepare query: %s", stmtID, query);
426455

@@ -643,6 +672,13 @@ bool MySQL::PrepExecute(int stmtID)
643672
return false;
644673
}
645674

675+
if (!connection) {
676+
if (!Reconnect()) {
677+
logger->Err("[Stmt %d] PrepExecute: Not connected.", stmtID);
678+
return FALSE;
679+
}
680+
}
681+
646682
logger->Info("[Stmt %d] PrepExecute: execute stmt", stmtID);
647683

648684
auto& stmt = m_prepStmts[stmtID - 1]->stmt;

src/plugins/xp_mysql/mysql_plugin.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ class MySQL : public DBPlugin {
4141
BYTE* ReadScorcoData(char* param, int* size) override;
4242

4343
private:
44-
bool Connect();
45-
void Disconnect();
44+
bool Connect() override;
45+
void Disconnect() override;
4646
bool Reconnect();
4747
bool Execute(char* query) override;
4848
int Fetch(char* buffer) override;
3.38 KB
Binary file not shown.

0 commit comments

Comments
 (0)