PRC8/nwn/nwnprc/trunk/include/inc_sql.nss

316 lines
9.9 KiB
Plaintext
Raw Blame History

/**
* @file
* All the functions dealing with the NWNx database. Based on the APS include
* with optimisations, renamed to avoid naming clashes with the APS system.
* @author Primogenitor, motu99, fluffyamoeba
* @date created on 2009-01-25
*/
#include "prc_inc_switch"
const int PRC_SQL_ERROR = 0;
const int PRC_SQL_SUCCESS = 1;
const string XCHST_DB = "xchst_db";
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
// creates and stores a 1024 Byte string for database-fetches on the module
void PRC_SQLInit();
// executes an SQL command direclty
void PRC_SQLExecDirect(string sSQL);
// fetches data from a previous SQL fetch request; returns TRUE is fetch was successful
int PRC_SQLFetch();
// gets the actual data from a fetch; if a table with more than 1 column was requested, return the table element at column iCol
string PRC_SQLGetData(int iCol);
// SQLite and MYSQL use different syntaxes
string PRC_SQLGetTick();
// Problems can arise with SQL commands if variables or values have single quotes
// in their names. These functions are a replace these quote with the tilde character
string ReplaceSingleChars(string sString, string sTarget, string sReplace);
// only needed for SQLite; commits (actually stores) the changed to the database
void PRC_SQLiteCommit();
// starts the pseudo heartbeat for committing SQLite DB
void StartSQLiteCommitHB();
// pseudo heartbeat for committing SQLite DB; interval given in switch PRC_DB_SQLITE_INTERVAL
// default is 600 seconds (= 10 min)
void SQLiteCommitHB();
// Set oObject's persistent object with sVarName to sValue
// Optional parameters:
// iExpiration: Number of days the persistent variable should be kept in database (default: 0=forever)
// sTable: Name of the table where variable should be stored (default: pwobjdata)
void PRC_SetPersistentObject(object oObject, string sVarName, object oObject2, int iExpiration = 0, string sTable = "pwobjdata");
// Get oObject's persistent object sVarName
// Optional parameters:
// sTable: Name of the table where object is stored (default: pwobjdata)
// * Return value on error: 0
object PRC_GetPersistentObject(object oObject, string sVarName, object oOwner = OBJECT_INVALID, string sTable = "pwobjdata");
// Portable presistent chest system (X-Chest) nwnx database support
//
void CreateXChestDB_SQLite();
void CreateXChestDB_MySQL();
void DeleteXChestDB();
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
void PRC_SQLInit()
{
int i;
// Placeholder for ODBC persistence
string sMemory;
for (i = 0; i < 8; i++) // reserve 8*128 bytes
sMemory +=
"................................................................................................................................";
SetLocalString(GetModule(), "NWNX!ODBC!SPACER", sMemory);
}
void PRC_SQLExecDirect(string sSQL)
{
SetLocalString(GetModule(), "NWNX!ODBC!EXEC", sSQL);
}
int PRC_SQLFetch()
{
string sRow;
object oModule = GetModule();
// initialize the fetch string to a large 1024 Byte string; this will also trigger the fetch operation in NWNX
SetLocalString(oModule, "NWNX!ODBC!FETCH", GetLocalString(oModule, "NWNX!ODBC!SPACER"));
// get the result from the fetch
sRow = GetLocalString(oModule, "NWNX!ODBC!FETCH");
if (GetStringLength(sRow) > 0)
{
// store the result on the module and signal success
SetLocalString(oModule, "NWNX_ODBC_CurrentRow", sRow);
return PRC_SQL_SUCCESS;
}
else
{
// set the result string on the module to empty and signal failure
SetLocalString(oModule, "NWNX_ODBC_CurrentRow", "");
return PRC_SQL_ERROR;
}
}
/** @todo check mySQL manual, not sure if this is needed - fluffyamoeba */
string PRC_SQLGetTick()
{
if(GetPRCSwitch(PRC_DB_SQLITE))
{
return "";
}
else
{
return "`";
}
}
string PRC_SQLGetData(int iCol)
{
string sResultSet = GetLocalString(GetModule(), "NWNX_ODBC_CurrentRow");
int iPos = FindSubString(sResultSet, "<22>");
if (iCol == 1)
{
// only one column returned ? Then we are finished
if (iPos == -1) return sResultSet;
// more than one column returned ? Then return first column
else return GetStringLeft(sResultSet, iPos);
}
// more than one column requested, but only one returned ? Something went wrong; return empty string
else if (iPos == -1) return "";
// find column in current row
int iCount = 0;
int nLength = GetStringLength(sResultSet);
// loop through columns until found
while (iCount++ != iCol)
{
if (iCount == iCol)
return GetStringLeft(sResultSet, iPos);
// pull off the previous column and find new column marker
nLength -= (iPos + 1);
sResultSet = GetStringRight(sResultSet, nLength);
iPos = FindSubString(sResultSet, "<22>");
// special case: last column in row
if (iPos == -1) return sResultSet;
}
return sResultSet;
}
string ReplaceSingleChars(string sString, string sTarget, string sReplace)
{
if (FindSubString(sString, sTarget) == -1) // not found
return sString;
int i;
string sReturn = "";
string sChar;
// Loop over every character and replace special characters
for (i = 0; i < GetStringLength(sString); i++)
{
sChar = GetSubString(sString, i, 1);
if (sChar == sTarget)
sReturn += sReplace;
else
sReturn += sChar;
}
return sReturn;
}
// only needed for SQLite; commits (actually stores) the changed to the database
void PRC_SQLiteCommit()
{
PRC_SQLExecDirect("COMMIT");
PRC_SQLExecDirect("BEGIN IMMEDIATE");
}
// starts the pseudo heartbeat for committing SQLite DB
void StartSQLiteCommitHB()
{
if (GetPRCSwitch(PRC_DB_SQLITE))
{
int nInterval = GetPRCSwitch(PRC_DB_SQLITE_INTERVAL);
DelayCommand(nInterval ? IntToFloat(nInterval) : 600.0f, SQLiteCommitHB());
}
}
// pseudo heartbeat for committing SQLite DB; interval given in switch PRC_DB_SQLITE_INTERVAL
// default is 600 seconds (= 10 min)
void SQLiteCommitHB()
{
// check if we are still using SQLite
if (GetPRCSwitch(PRC_DB_SQLITE))
{
// do the commit
PRC_SQLExecDirect("COMMIT");
PRC_SQLExecDirect("BEGIN IMMEDIATE");
// continue pseudo heartbeat
int nInterval = GetPRCSwitch(PRC_DB_SQLITE_INTERVAL);
DelayCommand(nInterval ? IntToFloat(nInterval) : 600.0f, SQLiteCommitHB());
}
}
void PRC_SetPersistentObject(object oOwner, string sVarName, object oObject, int iExpiration = 0, string sTable = "pwobjdata")
{
string sPlayer;
string sTag;
if (GetIsPC(oOwner))
{
sPlayer = ReplaceSingleChars(GetPCPlayerName(oOwner), "'", "~");
sTag = ReplaceSingleChars(GetName(oOwner), "'", "~");
}
else
{
sPlayer = "~";
sTag = GetTag(oOwner);
}
sVarName = ReplaceSingleChars(sVarName, "'", "~");
string sSQL = "SELECT player FROM " + sTable + " WHERE player='" + sPlayer +
"' AND tag='" + sTag + "' AND name='" + sVarName + "'";
PRC_SQLExecDirect(sSQL);
if (PRC_SQLFetch() == PRC_SQL_SUCCESS)
{
// row exists
sSQL = "UPDATE " + sTable + " SET val=%s,expire=" + IntToString(iExpiration) +
" WHERE player='" + sPlayer + "' AND tag='" + sTag + "' AND name='" + sVarName + "'";
SetLocalString(GetModule(), "NWNX!ODBC!SETSCORCOSQL", sSQL);
StoreCampaignObject ("NWNX", "-", oObject);
}
else
{
// row doesn't exist
sSQL = "INSERT INTO " + sTable + " (player,tag,name,val,expire) VALUES" +
"('" + sPlayer + "','" + sTag + "','" + sVarName + "',%s," + IntToString(iExpiration) + ")";
SetLocalString(GetModule(), "NWNX!ODBC!SETSCORCOSQL", sSQL);
StoreCampaignObject ("NWNX", "-", oObject);
}
}
object PRC_GetPersistentObject(object oObject, string sVarName, object oOwner = OBJECT_INVALID, string sTable = "pwobjdata")
{
string sPlayer;
string sTag;
object oModule;
if (GetIsPC(oObject))
{
sPlayer = ReplaceSingleChars(GetPCPlayerName(oObject), "'", "~");
sTag = ReplaceSingleChars(GetName(oObject), "'", "~");
}
else
{
sPlayer = "~";
sTag = GetTag(oObject);
}
sVarName = ReplaceSingleChars(sVarName, "'", "~");
string sSQL = "SELECT val FROM " + sTable + " WHERE player='" + sPlayer +
"' AND tag='" + sTag + "' AND name='" + sVarName + "'";
SetLocalString(GetModule(), "NWNX!ODBC!SETSCORCOSQL", sSQL);
if (!GetIsObjectValid(oOwner))
oOwner = oObject;
return RetrieveCampaignObject ("NWNX", "-", GetLocation(oOwner), oOwner);
}
//////////////////////////////////////////////////
/* Functions for portable persistent chest */
//////////////////////////////////////////////////
void DeleteXChestDB()
{
PRC_SQLExecDirect("DROP TABLE "+XCHST_DB);
}
void CreateXChestDB_SQLite()
{
PRC_SQLExecDirect("CREATE TABLE "+XCHST_DB+" (" +
"player varchar(64) NOT NULL default '~'," +
"tag varchar(64) NOT NULL default '~'," +
"name varchar(64) NOT NULL default '~'," +
"val blob," +
"expire int(11) default NULL," +
"last timestamp NOT NULL default current_timestamp," +
"PRIMARY KEY (player,tag,name)" +
")");
}
void CreateXChestDB_MySQL()
{
PRC_SQLExecDirect("CREATE TABLE "+XCHST_DB+" (" +
"player varchar(64) NOT NULL default '~'," +
"tag varchar(64) NOT NULL default '~'," +
"name varchar(64) NOT NULL default '~'," +
"val blob," +
"expire int(11) default NULL," +
"last timestamp NOT NULL default CURRENT_TIMESTAMP," +
"PRIMARY KEY (player,tag,name)" +
") ENGINE=MyISAM DEFAULT CHARSET=latin1;");
}
//:: void main (){}