Проблемы с SQL_ThreadQuery

Сообщения
74
Реакции
61
Помог
1 раз(а)
Всем привет! Нужен совет.

У меня есть самописный плагин на ЛИЧНЫЙ КАБИНЕТ. Там всё хорошо, но есть другие плагины, использующие этот плагин. К примеру, плагин статистики: берёт от ЛК дескриптор подключения к БД и форвардом логин зарегистрированного человека. В момент как игрок зарегистрировался статистика создает столбец под статистику в БД. Из-за того что на **дской MyARENA устаревшя БД,мне пришлось сделать квар для альтернативного синтаксиса:


C++:
//Заход/Регистрация (проверяем существует ли столбец с данными игрока, если нет - создаём)
//Регистрация и вход не срабатывает одновременно (если что). Если регистрация, то авторизация не вызывается
public dc_user_register(pId, szLogin[], szAuth[34]) {
    dc_user_auth(pId, szAuth);
}
public dc_user_auth(pId, szAuth[34]) {
    if(!g_iCvarDBSyntax) {
        new szData[2], szBuffer[2048]; szData[0] = pId;
        formatex(szBuffer, charsmax(szBuffer), "insert into `%s` (`%s`) Select '%s' Where not exists(select * from `%s` where `%s` = '%s');",
        g_szTable, STATS_TABLE_LOGIN_NAME, szAuth,        g_szTable, STATS_TABLE_LOGIN_NAME, szAuth);
        SQL_ThreadQuery(g_hTupleSql, "@SQL_IgnoreHandle", szBuffer);
        SQL_ThreadQuery(g_hTupleSql, "@SQL_ConnectHandle", fmt("SELECT * FROM `%s` WHERE `%s` = '%s'", g_szTable, STATS_TABLE_LOGIN_NAME, szAuth),
        szData, sizeof szData);
    } else {
        CheckCreateAccount(pId, szAuth);
    }
}

//Сама функция CheckCreateAccount
//Отправляем запрос в БД
CheckCreateAccount(pId, szLogin[]) {
    new szData[2]; szData[0] = pId;
    SQL_ThreadQuery(g_hTupleSql, "@SQL_CreateAccount", fmt("SELECT * FROM `%s` WHERE `%s` = '%s';",
    g_szTable, STATS_TABLE_LOGIN_NAME, szLogin),
    szData, sizeof szData);
}

@SQL_CreateAccount(iFailState, Handle:hQuery, const szError[], iError, const szData[], iDataSize) {
    if(g_hTupleSql == Empty_Handle) return PLUGIN_HANDLED;
    switch(iFailState) {
        case TQUERY_CONNECT_FAILED: {
            log_amx("ERROR: MySQL connection failed");
            log_amx("[ %d ] %s", iError, szError );         
            return PLUGIN_HANDLED;
        }     
        case TQUERY_QUERY_FAILED: {
            log_amx("ERROR: MySQL query failed");
            log_amx("[ %d ] %s", iError, szError );     
            return PLUGIN_HANDLED;
        }
    }

    new pId = szData[0];
    new szLogin[35];
    if(is_user_connected(pId)) dc_account(DC_UserGetKey, pId, szLogin);
    else copy(szLogin, charsmax(szLogin), "server");
  
    //Столбцы не найдены с логином? Создаём
    if(SQL_NumResults(hQuery) < 1) { //Игрок не найден
        SQL_FreeHandle(hQuery);
        SQL_ThreadQuery(g_hTupleSql, "@SQL_IgnoreHandle", fmt("INSERT INTO `%s`(`%s`) VALUES ('%s')",
        g_szTable, STATS_TABLE_LOGIN_NAME, szLogin));
    } else SQL_FreeHandle(hQuery);
 
    //Так как запрос на создание столбца приходит быстрее, мы сразу же
    //Загружаем уже в наши массивы данные игрока
    new szDataNew[2]; szDataNew[0] = pId;
    SQL_ThreadQuery(g_hTupleSql, "@SQL_ConnectHandle", fmt("SELECT * FROM `%s` WHERE `%s` = '%s'", g_szTable, STATS_TABLE_LOGIN_NAME, szLogin), szDataNew, sizeof szDataNew);
    return PLUGIN_HANDLED;
}
В режиме работы через CheckCreateAccount мне часто пишет:

C++:
L 08/02/2021 - 12:00:43: [MySQL] Thread worker was unable to start.
L 08/02/2021 - 12:00:43: [AMXX] Displaying debug trace (plugin "ujbl_dc_stats.amxx", version "vk/krisiso")
L 08/02/2021 - 12:00:43: [AMXX] Run time error 10: native error (native "SQL_ThreadQuery")
L 08/02/2021 - 12:00:43: [AMXX]    [0] ujbl_dc_stats.sma::@SQL_CreateAccount (line 731)
L 08/02/2021 - 13:42:08: Start of error session.
Кто может подсказать, как можно избавится от данной ошибки? Синхронный запрос нелать не вариант через SQL_PrepareQuery
Тасками всё фигарить тоже не охота, придётся все 1500 строк кода переписывать под задержки (и это в одном плагине только). Самих плагинов у меня около 5, (которые работают через форвард авторизации) и все бывает ругаются

Ошибка раздражает, у людей не всегда создаётся статистика. А с клиентами из MyArena этот вопрос можно решить лишь переездном на другую БД
2 Авг 2021
И правда, а чего я парюсь. Чего сразу не получить в этой функции данные для статистики, правда придётся везде переписать. Спасибо мне, что придумал решение, когда уже опубликовал тему
2 Авг 2021
Если у кого есть совет как по-другому реализовать этот момент, я буду очень благодарен
 
Последнее редактирование:
Сообщения
1,576
Реакции
658
Помог
5 раз(а)
AnonymousAmx, перед запуском плагина или после выгрузки плагина, вылетает эта ошибка. Сам сталкивался и решения нет скорее всего.
 
Сообщения
74
Реакции
61
Помог
1 раз(а)
karaulov, если ругается при запуске, когда подключаешься к БД и проверяешь через SQL_Connect (вылет нечастый) или просто само по себе (пишет мол ошибка коннекта к бд), то это проблема в БД.

Ответ моей ТП по вебхосту:

C++:
Jul 31 15:49:54 server139 mysqld[13146]: 2021-07-31T12:49:54.719041Z 43318720 [Note] Aborted connection 43318720 to db: 'u1420977_igor' user: 'u1420977_igor' host: 'ip'
(Got an error reading communication packets)
Jul 31 15:50:36 server139 mysqld[13146]: 2021-07-31T12:50:34.362973Z 43319501 [Note] Aborted connection 43319501 to db: 'u1420977_igor' user: 'u1420977_igor' host: 'ip'
(Got an error reading communication packets)
Jul 31 15:53:16 server139 mysqld[13146]: 2021-07-31T12:53:16.304399Z 43322293 [Note] Aborted connection 43322293 to db: 'u1420977_igor' user: 'u1420977_igor' host: 'ip'
(Got an error reading communication packets)

Сообщение:
Для их решения необходимо вносить изменения в настройки mysql, что на сервере виртуального хостинга невозможно:
https://www.percona.com/blog/2016/05/16/mysql-got-an-error-reading-communication-packet-errors/

Для решения данной проблемы рекомендуем перенести базу данных на VPS, так как на услуге виртуального хостинга может возникать данная проблема и решить её в рамках вашей услуги не представляется возможным.

Дополнительная информация:
https://www.reg.ru/support/hosting-i-servery/perenos_saitov/kak-pereyti-s-virtualnogo-khostinga-na-vps-khosting
А на счет моей проблемы с Thread, я сделал чуть по-другому сминимальным количеством тасков.:

C++:
@SQL_ConnectHandle(iFailState, Handle:hQuery, const szError[], iError, const szData[], iDataSize) {
    if(g_hTupleSql == Empty_Handle) return PLUGIN_HANDLED;
    switch(iFailState) {
        case TQUERY_CONNECT_FAILED: {
            log_amx("ERROR: MySQL connection failed");
            log_amx("[ %d ] %s", iError, szError );          
            return PLUGIN_HANDLED;
        }      
        case TQUERY_QUERY_FAILED: {
            log_amx("ERROR: MySQL query failed");
            log_amx("[ %d ] %s", iError, szError );      
            return PLUGIN_HANDLED;
        }
    }

    new pId = szData[0], iPos;
    if(SQL_NumResults(hQuery) == 1) {
        new iColumn;
        if(!pId) {      
            for(iPos = 0; iPos < _:eData_Stats; iPos++) {
                if(eData_Stats:iPos == Stat_BitAchievements) continue;
                iColumn = SQL_FieldNameToNum(hQuery, g_szStatsName[eData_Stats:iPos]);
                if(iColumn > -1) g_iGlobalStats[eData_Stats:iPos] = SQL_ReadResult(hQuery, iColumn);          
                iColumn = -1;      
            }
        } else {
            new szBuffer[64];
            for(iPos = 0; iPos < _:eData_Stats; iPos++) {
                iColumn = SQL_FieldNameToNum(hQuery, g_szStatsName[eData_Stats:iPos]);
                if(iColumn > -1) {
                    if(eData_Stats:iPos == Stat_BitAchievements) {
                        SQL_ReadResult(hQuery, iColumn, szBuffer, charsmax(szBuffer));  
                        g_iUserStats[pId][eData_Stats:iPos] = str_to_num(szBuffer);
                    }                      
                    else
                        g_iUserStats[pId][eData_Stats:iPos] = SQL_ReadResult(hQuery, iColumn);      
                }
                iColumn = -1;      
            }
        }
    } else {
        if(!g_iCvarDBSyntax) {
            SQL_FreeHandle(hQuery);
            return PLUGIN_HANDLED;
        }
        if(!pId) {      
            for(iPos = 0; iPos < _:eData_Stats; iPos++) {
                g_iGlobalStats[eData_Stats:iPos] = g_iNameDefaultValue[eData_Stats:iPos];
            }
        } else {
            for(iPos = 0; iPos < _:eData_Stats; iPos++) {
                g_iUserStats[pId][eData_Stats:iPos]    = g_iNameDefaultValue[eData_Stats:iPos];
            }
        }
        set_task(0.1, "@TK_CreateAccout", pId + 51518921);
    }
    SQL_FreeHandle(hQuery);
    return PLUGIN_HANDLED;
}

@TK_CreateAccout(pId) {
    pId -= 51518921;
    new szLogin[35];
    if(is_user_connected(pId)) dc_account(DC_UserGetKey, pId, szLogin);
    else copy(szLogin, charsmax(szLogin), "server");
    SQL_ThreadQuery(g_hTupleSql, "@SQL_IgnoreHandle", fmt("INSERT INTO `%s`(`%s`) VALUES ('%s')", g_szTable, STATS_TABLE_LOGIN_NAME, szLogin));
}
Вроде пару часов как полёт нормальный, не ругалось ещё
 
Сообщения
673
Реакции
242
Помог
11 раз(а)
не особо понял суть проблему, но возможно словил (не точно, сразу говорю), делай запросы поточными т.е. один запрос = 1 поток

Код:
enum _:sql_que_type
{
    SQL_CREATE,
    SQL_ROW
}
//Заход/Регистрация (проверяем существует ли столбец с данными игрока, если нет - создаём)
//Регистрация и вход не срабатывает одновременно (если что). Если регистрация, то авторизация не вызывается
public dc_user_register(pId, szLogin[], szAuth[34]) {
    dc_user_auth(pId, szAuth);
}
public dc_user_auth(pId, szAuth[34]) {
    //Не понял логику????
    /*
    if(!g_iCvarDBSyntax)
    {
        new szData[3], szBuffer[2048]; szData[0] = pIdб szData[1] = SQL_ROW;
        formatex(szBuffer, charsmax(szBuffer), "insert into `%s` (`%s`) Select '%s' Where not exists(select * from `%s` where `%s` = '%s');",
        g_szTable, STATS_TABLE_LOGIN_NAME, szAuth,        g_szTable, STATS_TABLE_LOGIN_NAME, szAuth);
        SQL_ThreadQuery(g_hTupleSql, "@SQL_IgnoreHandle", szBuffer);
    
    
        SQL_ThreadQuery(g_hTupleSql, "@SQL_ConnectHandle", fmt("SELECT * FROM `%s` WHERE `%s` = '%s'", g_szTable, STATS_TABLE_LOGIN_NAME, szAuth),
        szData, sizeof szData);
    } else {
        CheckCreateAccount(pId, szAuth);
    }*/
    CheckCreateAccount(pId, szAuth);
}
//Сама функция CheckCreateAccount
//Отправляем запрос в БД
CheckCreateAccount(pId, szLogin[]) {
    new szData[3];
    szData[0] = pId;
    szData[1] = SQL_CREATE;
    SQL_ThreadQuery(g_hTupleSql, "@SQL_CreateAccount", fmt("SELECT * FROM `%s` WHERE `%s` = '%s';",
    g_szTable, STATS_TABLE_LOGIN_NAME, szLogin),
    szData, sizeof szData);
}
@SQL_CreateAccount(iFailState, Handle:hQuery, const szError[], iError, const szData[], iDataSize) {
    if(g_hTupleSql == Empty_Handle) return PLUGIN_HANDLED;
    switch(iFailState) {
    case TQUERY_CONNECT_FAILED: {
            log_amx("ERROR: MySQL connection failed");
            log_amx("[ %d ] %s", iError, szError );      
            return PLUGIN_HANDLED;
        }  
    case TQUERY_QUERY_FAILED: {
            log_amx("ERROR: MySQL query failed");
            log_amx("[ %d ] %s", iError, szError );  
            return PLUGIN_HANDLED;
        }
    }
    new pId = szData[0];
    new szLogin[35];
    if(is_user_connected(pId)) dc_account(DC_UserGetKey, pId, szLogin);
    else copy(szLogin, charsmax(szLogin), "server");
    new szDataNew[3];
    switch(szData[1])
    {
    case SQL_CREATE:
        {
            //Столбцы не найдены с логином? Создаём
            if(!SQL_NumResults(hQuery)) { //Игрок не найден
                {
                    szDataNew[0] = pId;
                    szDataNew[1] = SQL_CREATE;
                    
                    SQL_ThreadQuery(g_hTupleSql, "@SQL_CreateAccount", fmt("INSERT INTO `%s`(`%s`) VALUES ('%s')",    g_szTable, STATS_TABLE_LOGIN_NAME, szLogin));
                }
                else
                //Данные найдены?
                {
                    szDataNew[0] = pId;
                    szDataNew[1] = SQL_ROW;
                    SQL_ThreadQuery(g_hTupleSql, "@SQL_CreateAccount", fmt("SELECT * FROM `%s` WHERE `%s` = '%s'", g_szTable, STATS_TABLE_LOGIN_NAME, szLogin), szDataNew, sizeof szDataNew);
                }
                
            }
            //Получаем данные на основе запроса SQL_ROW
        case SQL_ROW:
            {
                if( SQL_NumResults( hQuery ) )
                {
                    
                    {
                        new iColumn;
                        if(!pId) {    
                            for(iPos = 0; iPos < _:eData_Stats; iPos++) {
                                if(eData_Stats:iPos == Stat_BitAchievements) continue;
                                iColumn = SQL_FieldNameToNum(hQuery, g_szStatsName[eData_Stats:iPos]);
                                if(iColumn > -1) g_iGlobalStats[eData_Stats:iPos] = SQL_ReadResult(hQuery, iColumn);        
                                iColumn = -1;    
                            }
                        } else {
                            new szBuffer[64];
                            for(iPos = 0; iPos < _:eData_Stats; iPos++) {
                                iColumn = SQL_FieldNameToNum(hQuery, g_szStatsName[eData_Stats:iPos]);
                                if(iColumn > -1) {
                                    if(eData_Stats:iPos == Stat_BitAchievements) {
                                        SQL_ReadResult(hQuery, iColumn, szBuffer, charsmax(szBuffer));
                                        g_iUserStats[pId][eData_Stats:iPos] = str_to_num(szBuffer);
                                    }                    
                                    else
                                    g_iUserStats[pId][eData_Stats:iPos] = SQL_ReadResult(hQuery, iColumn);    
                                }
                                iColumn = -1;    
                            }
                        }
                    }
                }
            }
        }
        return PLUGIN_HANDLED;
    }
 
Последнее редактирование:
Сообщения
99
Реакции
75
Помог
1 раз(а)
Shutdown the server, reinstall AmxModX properly, then the problem should disappear.
3 Авг 2021
I can't edit the message from above, sorry for double post.

And this problem seems to happen only for SQL_ThreadQuery (), you can try using SQL_Execute ().
Код:
static cell AMX_NATIVE_CALL SQL_ThreadQuery(AMX *amx, cell *params)
{
    if (!g_pWorker)
    {
        MF_LogError(amx, AMX_ERR_NATIVE, "Thread worker was unable to start.");
        return 0;
    }

    SQL_Connection *cn = (SQL_Connection *)GetHandle(params[1], Handle_Connection);
    if (!cn)
    {
        MF_LogError(amx, AMX_ERR_NATIVE, "Invalid info tuple handle: %d", params[1]);
        return 0;
    }

    int len;
    const char *handler = MF_GetAmxString(amx, params[2], 0, &len);
    int fwd = MF_RegisterSPForwardByName(amx, handler, FP_CELL, FP_CELL, FP_STRING, FP_CELL, FP_ARRAY, FP_CELL, FP_CELL, FP_DONE);
    if (fwd < 1)
    {
        MF_LogError(amx, AMX_ERR_NATIVE, "Function not found: %s", handler);
        return 0;
    }

    MysqlThread *kmThread;
    g_QueueLock->Lock();
    if (g_FreeThreads.empty())
    {
        kmThread = new MysqlThread();
    }
    else
    {
        kmThread = g_FreeThreads.front();
        g_FreeThreads.pop();
    }
    g_QueueLock->Unlock();

    kmThread->SetInfo(cn->host, cn->user, cn->pass, cn->db, cn->port, cn->max_timeout);
    kmThread->SetForward(fwd);
    kmThread->SetQuery(MF_GetAmxString(amx, params[3], 1, &len));
    kmThread->SetCellData(MF_GetAmxAddr(amx, params[4]), (ucell)params[5]);
    kmThread->SetCharacterSet(cn->charset);

    g_pWorker->MakeThread(kmThread);

    return 1;
}
 
Сообщения
74
Реакции
61
Помог
1 раз(а)
@неопределенный, thanks, took note : good2:
 

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу