Check out this code. Requires
Code:
// Generalized table query for MySQL:
/*
CREATE TABLE IF NOT EXISTS %s (classkey VARCHAR(64),value TEXT,UNIQUE KEY (classkey))
*/
// Generalized table query for SQLite:
/*
CREATE TABLE IF NOT EXISTS %s (classkey VARCHAR(64),value TEXT,UNIQUE (classkey))
*/
new TravTrie:g_ClassArray
// ...
public _ARP_ClassLoad(Plugin,Params)
{
if(Params != 4)
{
format(g_Query,4095,"Parameters do not match. Expected: 3, Found: %d",Params)
return UTIL_ARP_ThrowError(AMX_ERR_NATIVE,0,g_Query,Plugin)
}
new Param[64],Handler[64],Temp[128],Table[64],ClassName[128]//,Len = min(4095,get_param(4))
get_string(1,Param,63)
get_string(2,Handler,63)
get_string(3,g_Query,4095)
get_string(4,Table,63)
if(!Table[0])
copy(Table,63,g_DataTable)
format(ClassName,127,"%s|%s",Table,Param)
//g_Query[0] = Len
format(Temp,127,"%d|%s",Plugin,Handler)
new travTrieIter:Iter = GetTravTrieIterator(g_ClassArray),Cell,ClassHeader[64],Loaded,TravTrie:CurTrie,TravTrie:PluginTrie,Flag,ReadTable[64],Garbage[1]
while(MoreTravTrie(Iter))
{
ReadTravTrieKey(Iter,ClassHeader,63)
ReadTravTrieCell(Iter,Cell)
strtok(ClassHeader,ReadTable,63,Garbage,0,'|')
if(Table[0] && equali(ReadTable,Table))
Flag = 1
if(equali(ClassName,ClassHeader))
{
TravTrieGetCell(g_ClassArray,ClassHeader,CurTrie)
TravTrieGetHCell(CurTrie,"/plugins",PluginTrie)
TravTrieSetCellEx(PluginTrie,Plugin,1)
TravTrieGetHCell(CurTrie,"/loaded",Loaded)
if(!Loaded)
{
new TravTrie:CallsTrie
TravTrieGetHCell(CurTrie,"/calls",CallsTrie)
TravTrieSetString(CallsTrie,Temp,g_Query)
return -1
}
/*new Forward = CreateOneForward(Plugin,"ARP_ClassLoaded",FP_CELL,FP_STRING),Return
if(!Forward || !ExecuteForward(Forward,Return,_:CurTrie,Class))
{
format(g_Query,4095,"Could not execute ARP_ClassLoaded forward")
return UTIL_ARP_ThrowError(AMX_ERR_NATIVE,0,g_Query,Plugin)
}
DestroyForward(Forward)*/
new Forward = CreateOneForward(Plugin,Handler,FP_CELL,FP_STRING,FP_STRING),Return
//new CurArray = PrepareArray(g_Query[1],Len)
if(!Forward || !ExecuteForward(Forward,Return,_:CurTrie,ClassHeader,g_Query))
{
format(g_Query,4095,"Could not execute %s forward to %d",Handler,Plugin)
return UTIL_ARP_ThrowError(AMX_ERR_NATIVE,0,g_Query,Plugin)
}
DestroyForward(Forward)
return PLUGIN_HANDLED
}
}
DestroyTravTrieIterator(Iter)
if(!Flag && !equali(g_DataTable,Table))
{
static Query[512]
switch(g_SqlMode)
{
case MYSQL:
format(Query,511,"CREATE TABLE IF NOT EXISTS %s (classkey VARCHAR(64),value TEXT,UNIQUE KEY (classkey))",Table)
case SQLITE:
format(Query,511,"CREATE TABLE IF NOT EXISTS %s (classkey VARCHAR(64),value TEXT,UNIQUE (classkey))",Table)
}
UTIL_ARP_CleverQuery(g_Plugin,g_SqlHandle,"IgnoreHandle",Query)
}
new Buffer[128] //,TravTrie:CallTrie = TravTrieCreate()
//SQL_QuoteString(g_SqlHandle,Buffer,127,Param)
copy(Buffer,126,Param)
//server_print("Setting array: %d | %s | %s | %d",CallTrie,Handler,g_Query,Len)
new TravTrie:CallTrie = TravTrieCreate()
TravTrieSetString(CallTrie,Temp,g_Query)
CurTrie = TravTrieCreate()
TravTrieSetCell(g_ClassArray,ClassName,CurTrie)
TravTrieSetHCell(CurTrie,"/loaded",0)
TravTrieSetHCell(CurTrie,"/saving",0)
TravTrieSetHCell(CurTrie,"/lastquery",0)
TravTrieSetHCell(CurTrie,"/plugins",TravTrieCreate())
TravTrieSetHCell(CurTrie,"/changed",TravTrieCreate())
TravTrieSetHCell(CurTrie,"/calls",CallTrie)
TravTrieSetHCell(CurTrie,"/savetrie",TravTrieCreate())
TravTrieSetString(CurTrie,"/table",Table)
//TravTrieSetString(CurTrie,"/table",Table)
Buffer[127] = _:CurTrie
format(g_Query,4095,"SELECT * FROM %s WHERE classkey LIKE '%s|%%'",Table,Buffer)
//UTIL_ARP_CleverQuery(g_Plugin,g_SqlHandle,"ClassLoadHandle",g_Query,Buffer,128)
SQL_ThreadQuery(g_SqlHandle,"ClassLoadHandle",g_Query,Buffer,128)
return PLUGIN_CONTINUE
}
public ClassLoadHandle(FailState,Handle:Query,Error[],Errcode,Data[],DataSize)
{
if(FailState == TQUERY_CONNECT_FAILED)
{
format(g_Query,4095,"Could not connect to database: %s",Error)
return UTIL_ARP_ThrowError(0,0,g_Query,0)
}
else if(FailState == TQUERY_QUERY_FAILED)
{
format(g_Query,4095,"Internal error: %s",Error)
return UTIL_ARP_ThrowError(0,0,g_Query,0)
}
if(Errcode)
{
format(g_Query,4095,"Error on query: %s",Error)
return UTIL_ARP_ThrowError(0,0,g_Query,0)
}
new ClassKey[128],Key[64],Value[128],Garbage[2],TravTrie:CurTrie = TravTrie:Data[127],TravTrie:CallsTrie
while(SQL_MoreResults(Query))
{
SQL_ReadResult(Query,0,ClassKey,127)
strtok(ClassKey,Garbage,1,Key,63,'|')
SQL_ReadResult(Query,1,Value,127)
TravTrieSetString(CurTrie,Key,Value)
SQL_NextRow(Query)
}
TravTrieSetHCell(CurTrie,"/loaded",1)
TravTrieGetHCell(CurTrie,"/calls",CallsTrie)
new travTrieIter:Iter = GetTravTrieIterator(CallsTrie),Handler[64],Forward,Return,Temp[64],PluginStr[10],Plugin
while(MoreTravTrie(Iter))
{
ReadTravTrieKey(Iter,Temp,63)
strtok(Temp,PluginStr,9,Handler,63,'|')
Plugin = str_to_num(PluginStr)
ReadTravTrieString(Iter,g_Query,4095)
Forward = CreateOneForward(Plugin,Handler,FP_CELL,FP_STRING,FP_STRING)
//CurArray = PrepareArray(g_Query[1],g_Query[0])
if(!Forward || !ExecuteForward(Forward,Return,_:CurTrie,Data,g_Query))
{
format(g_Query,4095,"Could not execute %s forward to %d",Handler,Plugin)
return UTIL_ARP_ThrowError(AMX_ERR_NATIVE,0,g_Query,0)
}
DestroyForward(Forward)
}
DestroyTravTrieIterator(Iter)
TravTrieDestroy(CallsTrie)
Forward = CreateMultiForward("ARP_ClassLoaded",ET_IGNORE,FP_CELL,FP_STRING)
if(!Forward || !ExecuteForward(Forward,Return,_:CurTrie,Data))
{
format(g_Query,4095,"Could not execute ARP_ClassLoaded forward")
return UTIL_ARP_ThrowError(AMX_ERR_NATIVE,0,g_Query,0)
}
DestroyForward(Forward)
return PLUGIN_CONTINUE
}
public _ARP_ClassSave(Plugin,Params)
{
if(Params != 2)
{
format(g_Query,4095,"Parameters do not match. Expected: 2, Found: %d",Params)
return UTIL_ARP_ThrowError(AMX_ERR_NATIVE,0,g_Query,Plugin)
}
new TravTrie:ClassNum = TravTrie:get_param_byref(1),ProcClass[128],Close = get_param(2),travTrieIter:Iter = GetTravTrieIterator(g_ClassArray),TrieClass[64],TravTrie:CurTrie,TravTrie:PluginTrie,ClassName[64]
while(MoreTravTrie(Iter))
{
ReadTravTrieKey(Iter,TrieClass,63)
ReadTravTrieCell(Iter,CurTrie)
copy(ClassName,63,TrieClass[containi(TrieClass,"|") + 1])
if(CurTrie == ClassNum && !task_exists(_:CurTrie))
{
//SQL_QuoteString(g_SqlHandle,ProcClass,127,Class)
copy(ProcClass[1],126,TrieClass)
//format(g_Query,4095,"DELETE FROM %s WHERE classkey LIKE '%s|%%'",g_DataTable,ProcClass)
//UTIL_ARP_CleverQuery(g_Plugin,g_SqlHandle,"IgnoreHandle",g_Query)
ProcClass[0] = _:CurTrie
new TravTrie:SaveTrie
TravTrieGetHCell(CurTrie,"/savetrie",SaveTrie)
new travTrieIter:Iter = GetTravTrieIterator(SaveTrie),Handler[64],Temp[128],PluginStr[10],Plugin,Forward,Return
//server_print("ITERATOR: %d, SAVETRIE: %d",Iter,SaveTrie)
while(MoreTravTrie(Iter))
{
ReadTravTrieKey(Iter,Temp,127)
ReadTravTrieString(Iter,g_Query,4095)
strtok(Temp,PluginStr,9,Handler,63,'|')
Plugin = str_to_num(PluginStr)
//server_print("Calling forward to: %d , %s",Plugin,Handler)
Forward = CreateOneForward(Plugin,Handler,FP_CELL,FP_STRING,FP_STRING)
if(!Forward || !ExecuteForward(Forward,Return,CurTrie,ClassName,g_Query))
{
format(g_Query,4095,"Could not register forward")
return UTIL_ARP_ThrowError(AMX_ERR_NATIVE,0,g_Query,g_Plugin)
}
DestroyForward(Forward)
}
DestroyTravTrieIterator(Iter)
if(_CallEvent("Class_Save",ClassName,128))
return FAILED
if(Close)
{
TravTrieGetHCell(CurTrie,"/plugins",PluginTrie)
TravTrieDeleteKeyEx(PluginTrie,Plugin)
set_param_byref(1,_:Invalid_TravTrie)
}
SaveClass(CurTrie,ProcClass[1])
return SUCCEEDED
}
}
DestroyTravTrieIterator(Iter)
return SUCCEEDED
}
public SaveClass(TravTrie:CurTrie,ProcClass[])
{
new Saving
TravTrieGetHCell(CurTrie,"/saving",Saving)
if(Saving)
return SUCCEEDED
new TravTrie:ChangedTrie,Table[64],ClassName[64]//,Garbage[1]
TravTrieGetHCell(CurTrie,"/changed",ChangedTrie)
//TravTrieGetString(CurTrie,"/table",Table,63)
//TravTrieGetHCell(CurTrie,"/table",TableTrie)
//TravTrieGetStringEx(TableTrie,0,Table,63)
strtok(ProcClass,Table,63,ClassName,63,'|')
TravTrieSetHCell(CurTrie,"/saving",1)
new Key[128],Data[64],TrieClass[64]
Data[1] = _:CurTrie
copy(Data[2],60,ProcClass)
//format(g_Query,4095,"DELETE FROM %s WHERE classkey LIKE '%s|%%'",g_DataTable,ProcClass)
//UTIL_ARP_CleverQuery(g_Plugin,g_SqlHandle,"IgnoreHandle",g_Query)
new travTrieIter:Iter = GetTravTrieIterator(CurTrie),Changed,ChangedNum
// Run through it once to get the number
while(MoreTravTrie(Iter))
{
ReadTravTrieKey(Iter,TrieClass,63)
ReadTravTrieString(Iter,g_Query,4095)
TravTrieGetCell(ChangedTrie,TrieClass,Changed)
if(TrieClass[0] != '^n' && TrieClass[0] != '/' && Changed) ChangedNum++
Changed = 0
}
TravTrieSetHCell(CurTrie,"/lastquery",ChangedNum)
DestroyTravTrieIterator(Iter)
Iter = GetTravTrieIterator(CurTrie)
while(MoreTravTrie(Iter))
{
ReadTravTrieKey(Iter,TrieClass,63)
ReadTravTrieString(Iter,g_Query,4095)
TravTrieGetCell(ChangedTrie,TrieClass,Changed)
if(TrieClass[0] == '^0' || TrieClass[0] == '/' || !Changed) continue
TravTrieSetCell(ChangedTrie,TrieClass,0)
Changed = 0
//SQL_QuoteString(g_SqlHandle,Key,127,TrieClass)
copy(Key,127,TrieClass)
//SQL_QuoteString(g_SqlHandle,g_Cache,4095,g_Query)
copy(g_Cache,4095,g_Query)
Data[0]++
ARP_SqlEscape(ClassName,127)
ARP_SqlEscape(Key,127)
ARP_SqlEscape(g_Cache,4095)
//replace_all(ClassName,127,"'","\'")
//replace_all(Key,127,"'","\'")
//replace_all(g_Cache,4095,"'","\'")
switch(g_SqlMode)
{
case MYSQL:
format(g_Query,4095,"INSERT INTO %s VALUES ('%s|%s','%s') ON DUPLICATE KEY UPDATE value='%s'",Table,ClassName,Key,g_Cache,g_Cache)
case SQLITE:
format(g_Query,4095,"REPLACE INTO %s VALUES ('%s|%s','%s')",Table,ClassName,Key,g_Cache)
}
UTIL_ARP_CleverQuery(g_Plugin,g_SqlHandle,"ClassSaveHandle",g_Query,Data,64)
}
DestroyTravTrieIterator(Iter)
new TravTrie:PluginTrie,TravTrie:SaveTrie
TravTrieGetHCell(CurTrie,"/plugins",PluginTrie)
TravTrieGetHCell(CurTrie,"/savetrie",SaveTrie)
if(!ChangedNum && !TravTrieSize(PluginTrie) && g_SqlMode == SQLITE)
{
TravTrieDestroy(PluginTrie)
TravTrieDestroy(CurTrie)
TravTrieDestroy(ChangedTrie)
TravTrieDestroy(SaveTrie)
TravTrieDeleteKey(g_ClassArray,ProcClass)
}
return SUCCEEDED
}
public ClassSaveHandle(FailState,Handle:Query,Error[],Errcode,Data[],DataSize)
{
if(FailState == TQUERY_CONNECT_FAILED)
{
format(g_Query,4095,"Could not connect to database: %s",Error)
return UTIL_ARP_ThrowError(0,0,g_Query,0)
}
else if(FailState == TQUERY_QUERY_FAILED)
{
SQL_GetQueryString(Query,g_Query,4095)
format(g_Query,4095,"Internal error: %s^nQuery: %s",Error,g_Query)
return UTIL_ARP_ThrowError(0,0,g_Query,0)
}
if(Errcode)
{
format(g_Query,4095,"Error on query: %s",Error)
return UTIL_ARP_ThrowError(0,0,g_Query,0)
}
new LastQuery,TravTrie:CurTrie = TravTrie:Data[1]
TravTrieGetHCell(CurTrie,"/lastquery",LastQuery)
if(Data[0] == LastQuery && g_SqlMode != SQLITE)
{
TravTrieSetHCell(CurTrie,"/saving",0)
new TravTrie:PluginTrie,TravTrie:ChangedTrie,TravTrie:SaveTrie
TravTrieGetHCell(CurTrie,"/plugins",PluginTrie)
TravTrieGetHCell(CurTrie,"/changed",ChangedTrie)
TravTrieGetHCell(CurTrie,"/savetrie",SaveTrie)
if(!TravTrieSize(PluginTrie) && !g_PluginEnd)
{
TravTrieDestroy(PluginTrie)
TravTrieDestroy(CurTrie)
TravTrieDestroy(ChangedTrie)
TravTrieDestroy(SaveTrie)
TravTrieDeleteKey(g_ClassArray,Data[2])
}
//if(g_PluginEnd && g_LastOverallQuery == Data[2]) TravTrieDestroy(g_ClassArray)
}
return PLUGIN_CONTINUE
}
public _ARP_ClassSaveHook(Plugin,Params)
{
if(Params != 3)
{
format(g_Query,4095,"Parameters do not match. Expected: 3, Found: %d",Params)
return UTIL_ARP_ThrowError(AMX_ERR_NATIVE,0,g_Query,Plugin)
}
new TravTrie:CurTrie = TravTrie:get_param(1),Handler[64],Temp[128],TravTrie:SaveTrie
get_string(2,Handler,63)
get_string(3,g_Query,4095)
format(Temp,127,"%d|%s",Plugin,Handler)
TravTrieGetHCell(CurTrie,"/savetrie",SaveTrie)
TravTrieSetString(SaveTrie,Temp,g_Query)
return SUCCEEDED
}
public _ARP_ClassDeleteKey(Plugin,Params)
{
if(Params != 2)
{
format(g_Query,4095,"Parameters do not match. Expected: 2, Found: %d",Params)
return UTIL_ARP_ThrowError(AMX_ERR_NATIVE,0,g_Query,Plugin)
}
new TravTrie:ClassNum = TravTrie:get_param(1),Key[64]
get_string(2,Key,63)
if(Key[0] == '/' || Key[0] == '^n' || !Class)
return FAILED
new travTrieIter:Iter = GetTravTrieIterator(g_ClassArray),Cell,Name[64]
while(MoreTravTrie(Iter))
{
ReadTravTrieKey(Iter,Name,63)
ReadTravTrieCell(Iter,Cell)
if(Cell == _:ClassNum)
break
}
DestroyTravTrieIterator(Iter)
//if(!Name[0])
// return FAILED
format(g_Query,4095,"DELETE FROM %s WHERE classkey='%s|%s'",g_DataTable,Name,Key)
UTIL_ARP_CleverQuery(g_Plugin,g_SqlHandle,"IgnoreHandle",g_Query)
return TravTrieDeleteKey(ClassNum,Key)
}