Присоединить MySQL к MQ4 - страница 5

 
sergeev:

да, все работает идеально, но пока сделал только для MQL5

пример работы сверху в моем посте


Можете отправить кусочек кода касающийся mysql_fetch_row, разбираясь с Вашим примером не понятно как доставать ячейки когда результат состоит из нескольких строк и колонок.
 
Graff:

Можете отправить кусочек кода касающийся mysql_fetch_row, разбираясь с Вашим примером не понятно как доставать ячейки когда результат состоит из нескольких строк и колонок.

аналогично.

1. взяли mysql_num_rows, mysql_num_fields

2. получили указатель на массив указателей очередной строку mysql_fetch_row, и указатель на длины полей mysql_fetch_lengths

3. вытягиваем из массива длин в свой массив эти длины (через memcpy)

4. из указателя на массив указателей на поля вытягиваем этот массив указателей на поля (так как знвем mysql_num_fields)

5. Зная длины полей (полученный массив длин из fetch_lengths) и указатели на сами поля вытягиваем через memcpy данные в uchar массив каждого поля

6. возврат к п.2.

 
HIDDEN:
Крутил, вертел и так и эдак, у меня ничего не вышло на 4-ке. Иной раз даже терминал вываливается полностью.

Кирилл, у меня в MQL4 усё работает. тестил на 409 билде

вот пример для получения в string

#import "libmysql.dll"
    int mysql_get_client_info(); // функция вернула char*
#import "msvcrt.dll"
    int strcpy(string strDestination, int strSource); // копируем NULL-строку из source в байтовый массив 
#import

void start()
{
    int ptr; string data="123456789"; 
    ptr=mysql_get_client_info(); // получили указатель на строку
    strcpy(data, ptr); // скопировали его в массив
    Print("client_info="+data); // вывели на печать
}

результат
!sql USDCHF,M30: client_info=6.0.0

аналогично если сделать для целого массива
заменить надо на

    int strcpy(int &strDestination[], int strSource); // копируем NULL-строку из source в байтовый массив 
 
sergeev:

Кирилл, у меня в MQL4 усё работает. тестил на 409 билде

вот пример для получения в string

результат
!sql USDCHF,M30: client_info=6.0.0

аналогично если сделать для целого массива
заменить надо на

У меня тот же билд, но терминал падает.... Надо перепробовать на разных терминалах разных ДЦ.

Хотя это возможно зависит еще и от винды, я на win7 x64 тестирую.

 

HIDDEN:


xp/32

тогда копай разные варианты вызовов и отпиши сразу в сервисдеск по этот баг.

может они что посоветуют делать.

 
sergeev:

аналогично.

1. взяли mysql_num_rows, mysql_num_fields

2. получили указатель на массив указателей очередной строку mysql_fetch_row, и указатель на длины полей mysql_fetch_lengths

3. вытягиваем из массива длин в свой массив эти длины (через memcpy)

4. из указателя на массив указателей на поля вытягиваем этот массив указателей на поля (так как знвем mysql_num_fields)

5. Зная длины полей (полученный массив длин из fetch_lengths) и указатели на сами поля вытягиваем через memcpy данные в uchar массив каждого поля

6. возврат к п.2.



Почти получилось. На данном этапе удается достать только первую ячейку каждой строки. memcpy почему-то копирует в мои массивы только первый элемент. Целый вечер убил. Что я делаю не так?

Исходник, дамп, лог в приложении.

Файлы:
 
Graff:


Почти получилось. На данном этапе удается достать только первую ячейку каждой строки. memcpy почему-то копирует в мои массивы только первый элемент. Целый вечер убил. Что я делаю не так?

Исходник, дамп, лог в приложении.


есть замечания

1. применять функции UNICODE2ANSI вообще нет необходимости. У вас для этих целей есть CharArrayToStr и ShortArrayToStr

2. использовать string в функции strcpy(string strDestination, int strSource); я не пытался, все делал через массивы. Если вы знаете, что копируете из UTF кодировки БД, то лучше загнать данные в short массив.

3. вот здесь у вас техническая ошибка (из за которой все и идет наперекосяк)
memcpy(alens,lens,num_fields);

это ведь не однобайтовый массив типа uchar. надо memcpy(alens,lens,num_fields*sizeof(int));

 
sergeev:

есть замечания

1. применять функции UNICODE2ANSI вообще нет необходимости. У вас для этих целей есть CharArrayToStr и ShortArrayToStr

2. использовать string в функции strcpy(string strDestination, int strSource); я не пытался, все делал через массивы. Если вы знаете, что копируете из UTF кодировки БД, то лучше загнать данные в short массив.

3. вот здесь у вас техническая ошибка (из за которой все и идет наперекосяк)
memcpy(alens,lens,num_fields);

это ведь не однобайтовый массив типа uchar. надо memcpy(alens,lens,num_fields*sizeof(int));



Спасибо! Заработало. Планируете зарелизить класс или библиотеку для работы с мускулом?
 
Graff:

Спасибо! Заработало. Планируете зарелизить класс или библиотеку для работы с мускулом?

если есть потребность, то могу. просто надо ли объяснять, что и так понятно...

функций в этой libmysql штук 50 всего...

причем большая половина чисто сервисные. из нужных для работы десяток.

--------

а вообще как вы видите этот класс или библиотеку? какие функции она должна иметь?

сделать просто дубликаты из api функций, или задать какие то наборы действий в одну функцию?

 
sergeev:

если есть потребность, то могу. просто надо ли объяснять, что и так понятно...

функций в этой libmysql штук 50 всего...

причем большая половина чисто сервисные. из нужных для работы десяток.

--------

а вообще как вы видите этот класс или библиотеку? какие функции она должна иметь?



Я считаю, что просто описать функции libmysql.dll недостаточно. Класс должен предоставлять пользователю возможность просто и без усилий работать с базой.

Пример 1: подключение к БД. Чтоб подключиться к БД через мой хилый класс нужно вызвать конструктор класса, хотя внутри происходит целый ряд действий, о которых знать не всегда нужно и необходимо.

CMYSQL2::CMYSQL2(const string host="localhost",const string user="root",const string password="",const string database="database",const uint port=3306)
  {
   uchar _host[],_user[],_password[],_database[],_socket[];
   StringToCharArray(host,_host);
   StringToCharArray(user,_user);
   StringToCharArray(password,_password);
   StringToCharArray(database,_database);
// Connecting
   mysql=mysql_init(NULL);
   uint conn=mysql_real_connect(mysql,_host,_user,_password,_database,port,_socket,0);
   if(mysql==NULL || conn==NULL || mysql!=conn){ Print(__FUNCTION__,"-> MySQL connetion failure.");}
  }

Пример 2: получение многострочного и многоколоночного результата. Все, что нужно пользователю - скормить запрос и массив(структуру) для записи результата.

//+------------------------------------------------------------------+
//|  Returns string array as sql_results struct param and rows count
//+------------------------------------------------------------------+
uint CMYSQL2::GetArray(string query,sql_results &out[])
  {
   Query2(query);
   StoreResult();
   uint rows=GetNumRows();
   uint fields=GetNumFields();
   ArrayResize(out,rows);

   for(uint r=0;r<rows;r++)
     {
      ArrayResize(out[r].value,fields);
      string fr_res=mysql_fetch_row(result);
      
      for(uint f=0;f<fields;f++)
        {
         out[r].value[f]=get_cell_u(fr_res,f);//Print("3,",f,",",fields);
        }
     }
   FreeLastResult();
   return(rows);
  }

^ это старый код, нужен чтоб понять идею.

Так же может быть множество примеров по добавлению информации в БД.

Если просто использовать набор функций без проверок, то очень легко можно попасть на Access violation read to 0x00000000 in 'libmysql.dll' и завалить всю систему.

Готов рассмотреть возможность совместного создания открытого класса для работы с мускулом.