PDA

Просмотр полной версии : [Вопрос] Удобство в работе с MySQL



franked
16.02.2016, 23:00
Привет всем! Я тут недавно подумывал для себя функцию написать,чисто для удобства работы с MySQL плагином в павно. В общем,я очень часто экранирую допустим запросы,и каждый раз писать строку,и mysql_format потом еще и mysql_function_query порой не то, что бы надоедает,но и мешает,грязнит код,и становиться немного не удобнее работать. И я подумывал для себя написать допустим функцию Mysql_query,которая бы принимала сразу строку с SQL запросом и сразу параметры,которые бы подставились потом в SQL запрос. И тут я задумался,что параметров может быть допустим не 5,а больше,бывают разные случаи.(callback'и пока не учитываю,просто хочу научиться писать подобные функции) И по правде говоря,я не знаю как бы ее написать,я только лишь понял,что начало должно быть примерно таким:


stock Mysql_query(query_string[], {Float,_}:...)//ну примерно так
{
//И тут уже код экранизации и т.д
}



Но дело в том,что я наткнулся на тему (кликабельно) (http://forum.sa-mp.com/showthread.php?t=77000&page=1),в которой есть примеры функции,но там аргументы берутся через getarg (Собственно больше и никак не получиться вроде). А getarg, в случае если мы передали массив (ту же самую строку например),по символьно извлекает строку. И это все делать в цикле и прочее прочее как то тоже не вариант особо. Кто может подсказать показать,как ее можно реализовать? Допустим с помощью того же #emit на этом ассэмблере... Очень хотелось бы научиться писать функции такого рода :popcorn:

ziggi
16.02.2016, 23:16
От Y_Less:

#define BYTES_PER_CELL (cellbits / charbits)

stock SendClientMessageToAllf(color, fstring[], {Float, _}:...)
{
static const STATIC_ARGS = 2;
new n = (numargs() - STATIC_ARGS) * BYTES_PER_CELL;
if (n)
{
new message[144], arg_start, arg_end;
#emit CONST.alt fstring
#emit LCTRL 5
#emit ADD
#emit STOR.S.pri arg_start

#emit LOAD.S.alt n
#emit ADD
#emit STOR.S.pri arg_end
do
{
#emit LOAD.I
#emit PUSH.pri
arg_end -= BYTES_PER_CELL;
#emit LOAD.S.pri arg_end
}
while(arg_end > arg_start);

#emit PUSH.S fstring
#emit PUSH.C 144
#emit PUSH.ADR message

n += BYTES_PER_CELL * 3;
#emit PUSH.S n
#emit SYSREQ.C format

n += BYTES_PER_CELL;
#emit LCTRL 4
#emit LOAD.S.alt n
#emit ADD
#emit SCTRL 4

SendClientMessageToAll(color, message);
}
else
{
SendClientMessageToAll(color, fstring);
}
return 1;
}

Daniel_Cortez
17.02.2016, 05:58
От Y_Less:

#define BYTES_PER_CELL (cellbits / charbits)

stock SendClientMessageToAllf(color, fstring[], {Float, _}:...)
{
static const STATIC_ARGS = 2;
new n = (numargs() - STATIC_ARGS) * BYTES_PER_CELL;
if (n)
{
new message[144], arg_start, arg_end;
#emit CONST.alt fstring
#emit LCTRL 5
#emit ADD
#emit STOR.S.pri arg_start

#emit LOAD.S.alt n
#emit ADD
#emit STOR.S.pri arg_end
do
{
#emit LOAD.I
#emit PUSH.pri
arg_end -= BYTES_PER_CELL;
#emit LOAD.S.pri arg_end
}
while(arg_end > arg_start);

#emit PUSH.S fstring
#emit PUSH.C 144
#emit PUSH.ADR message

n += BYTES_PER_CELL * 3;
#emit PUSH.S n
#emit SYSREQ.C format

n += BYTES_PER_CELL;
#emit LCTRL 4
#emit LOAD.S.alt n
#emit ADD
#emit SCTRL 4

SendClientMessageToAll(color, message);
}
else
{
SendClientMessageToAll(color, fstring);
}
return 1;
}
Эта функция иногда приводит к крашам. Один из таких случаев приходилось наблюдать, когда я объявил её как экспортируемую (public) и пробовал вызвать через CallLocalFunction (только не спрашивайте, почему), также подойдёт SetTimerEx или CallRemoteFunction - главное, чтобы функция вызывалась из сервера, а не из другой функции на Pawn.

franked
17.02.2016, 11:19
Эта функция иногда приводит к крашам. Один из таких случаев приходилось наблюдать, когда я объявил её как экспортируемую (public) и пробовал вызвать через CallLocalFunction (только не спрашивайте, почему), также подойдёт SetTimerEx или CallRemoteFunction - главное, чтобы функция вызывалась из сервера, а не из другой функции на Pawn.

Блин,жалко :sad:. Как же тогда быть? Есть еще варианты,как можно писать подобные функции?

Daniel_Cortez
17.02.2016, 13:51
Блин,жалко :sad:. Как же тогда быть? Есть еще варианты,как можно писать подобные функции?
Функции вряд ли, а вот макрос можно попробовать.

franked
17.02.2016, 15:21
Функции вряд ли, а вот макрос можно попробовать.

Да,я тоже подумывал макросом,вот,что из этого вышло:


#define MySQL_SendSQuery(%0,%1,%2,%3) mysql_format(%0, %1, sizeof(%1), %2, %3),mysql_function_query(%0, %1, false, "", "")

Типа MySQL_SendSafetyQuery,где будет отправляться безопасный запрос без колбэка. Но вот не задача,не уж то придется для каждого случая свой макрос писать? К примеру,если я захочу примерно той же самой строкой (MySQL_SendCQuery типа CallBackQuery) написать безопасный запрос,как мне дать понять #define'у что под %4 будут передаваться аргументы в функцию mysql_function_query а не в mysql_format?

Я уже пробовал,нечто подобное:


#define MySQL_SendСQuery(%0,%1,%2,%3,%4,%5,%6) format(%1, sizeof(%1), %2, %3),mysql_function_query(%0, %1, true, %4, %5, %6)


Но в колбэк всеравно данные не поступают....

Попробовал сделать еще нечто вроде этого:


#define MySQL_Query(%0,%1[%2],%3(%4),%5(%6),%7) mysql_format(%0, %1, sizeof(%1)+%2, %3, %4),mysql_function_query(%0, %1, true, %5, %6, %7)


Немного усовершенствовал даже где-то,но все-равно что-то коллбэк не вызывается...Вроде работает. Однако,пока-что только с одним походу аргументом.

Я этот макрос заюзал в системе регистрации,и у меня нужный мне колбэк,куда передается playerid вызвался и все проделал,что нужно. Сейчас еще потестю,а пока что,походу только с одним параметром такая фича работает.

franked
17.02.2016, 16:53
А,все,вроде-бы работает,разобрался. Я передавал в callback 2ым аргументом строку,но делал это так: "ds[80]",нужно было убрать квадратные скобки (ну и собственно само значение в них),привык работать со sscanf...

Получается,некий готовый вариант будет выглядить примерно так:


#define MySQL_Query(%0,%1[%2],%3(%4),%5,%6(%7),%8) mysql_format(%0, %1, sizeof(%1)+(%2), %3, %4),mysql_function_query(%0, %1, %5, %6, %7, %8)
/*
Пояснения:
%0 - connectionHandle
%1 - Переменная,которая будет содержать отформатированный запрос
%2 - Если допустим хотим добавить в sizeof вычисления,такие как +24(MAX_PLAYER_NAME например) или даже вычесть те же самые маркеры в строке (%s например)
%3 - Сама строка SQL запроса,с маркерами,куда будут подставляться значения
%4 - Переменные,которые будут подставляться в будучи формаитрованную SQL строку
%5 - true/false т.е вешать или не вешать паблик-обработчик нашего запроса (Коллбэк короче).
%7 - формат[] аргументов, (как в sscanf'e(почти) dsif (где d -integer,s- string,i - integer,f - float ну и т.д. короче))
%8 - сами аргументы,которые передадутся в коллбэк
*/

//Использование:

new STR[80];
MySQL_Query(conID, STR[0], "SELECT * FROM `accounts` WHERE `Name` = '%s' LIMIT 1"(Player[playerid][pName]),true,"testQuery_result"("ds"),playerid,STR);

//Создадим тестовый коллбэк:
forward testQuery_result(playerid,str[]);
public testQuery_result(playerid,str[])
{
print("=====================================================================================");
printf("[+] testQuery_result MY ID IS: %d\n[+] AND MY STRING IS:\n [++] %s", playerid, str);
print("=====================================================================================");
//P.S я пока не стал извлекать из базы данные,т.к базу еще толком не доделал,поэтому такого примера достаточно думаю будет =)
}

//Пояснение "Использование":

new STR[80];//Создаем переменную,которая будет отформатирована

MySQL_Query(conID, STR[0], "SELECT * FROM `accounts` WHERE `Name` = '%s' LIMIT 1"(Player[playerid][pName]),true,"testQuery_result"("ds"),playerid,STR);//Фигачим по макросу

conID - и есть connectionHandle (он же %0)

STR - Переменная,содержащая отформатированный запрос (%1)

[0] - Укажем, что ничего не прибавлять/не вычитать в sizeof (Хотя по сути он просто сделает sizeof(STR) + 0) (%2)

"SELECT * FROM `accounts` WHERE `Name` = '%s' LIMIT 1" - SQL запрос с маркером,куда подтсавиться ник игрока (%3)

(Player[playerid][pName]) - в скобках укажем подставляемые параметры в SQL строку (как и в макросе) МЕЖДУ ЭТИМИ СКОБКАМИ НЕ ДОЛЖНО БЫТЬ ПРОБЕЛОВ,КАК И В МАКРОСЕ,ИНАЧЕ РУГАТЬСЯ БУДЕТ (по крайней мере у меня ругается) (%4)

true - Укажем,что мы будем использовать колбэк /*В случае FALSE описано ниже*/ (%5)

"testQuery_result" - Укажем название колбэка,который будем использовать (%6)

("ds") - Параметры аргументов,которые передадим в колбэк (ТАКЖЕ НЕ ДОЛЖНО БЫТЬ ПРОБЕЛОВ) (%7)

playerid,STR - Переменные,которые будет принимать наш колбэк,это id игрока и саму отредактированную строку запроса,которую мы через printf в консоли покажем (%8)

//В случае false,если мы не хотим вызывать колбэк:

вместо true ставим false

вместо "testQuery_result" ставим: ""

вместо ("ds") ставим: ("")

и НЕ вписываем playerid,STR,а пишем: ""

//думаю нет смысла пояснять если что и про сам колбэк...