isc_dsql_fetch + набор данных ~50тыс.=arithmetic exception?!

IBX, FIBPlus, UIB, ADO, .Net и прочее-прочее-прочее, в общем все, что относится к созданию приложений, работающих с InterBase, Firebird и Yaffil - клиент-серверных, трехзвенных, консольных и т.п.

Модератор: kdv

Ответить
sunduk4
Сообщения: 18
Зарегистрирован: 02 май 2006, 13:45

isc_dsql_fetch + набор данных ~50тыс.=arithmetic exception?!

Сообщение sunduk4 » 05 июн 2006, 16:13

Стандартный код -

Код: Выделить всё


    main_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(3));
    main_sqlda->sqln = 3;
    main_sqlda->sqld = 3;
    main_sqlda->version = 1;

    if (isc_dsql_prepare(status, &trans, &main_stmt, 0, main_select, 1,  NULL))
    {
        ERREXIT(status, 1)
    }

    isc_dsql_describe(status, &main_stmt, 1, main_sqlda);


    for (i=0, main_var = main_sqlda->sqlvar; i < main_sqlda->sqld; i++, main_var++)
      {
         main_dtype = (main_var->sqltype & ~1);
         switch(main_dtype)
         {
            case SQL_VARYING:
              main_var->sqldata = (char *)malloc(sizeof(char)*main_var->sqllen + 1);
              break;
            case SQL_TEXT:
              main_var->sqldata = (char *)malloc(sizeof(char)*main_var->sqllen);
              break;	       
            case SQL_LONG:
               main_var->sqldata = (char *)malloc(sizeof(long));
               break;
            case SQL_SHORT:
               main_var->sqldata = (char *)malloc(sizeof(short));
                break;
         } 
         if (main_var->sqltype & 1)
         {
            main_var->sqlind = (short *)malloc(sizeof(short));
         }
      } 

    if (isc_dsql_execute2(status, &trans, &main_stmt, 1, main_sqlda, NULL))
    {
        ERREXIT(status, 1)
    }

    isc_dsql_set_cursor_name(status, &main_stmt, "main_cursor", NULL);

    while ((main_fetch_stat = isc_dsql_fetch(status, &main_stmt, 1, main_sqlda)) == 0)
    {
       .....обработка данных....     
     }

    if (main_fetch_stat != 100L)
    {
        ERREXIT(status, 1)
    }

    if (isc_dsql_free_statement(status, &main_stmt, DSQL_close))
    {
        ERREXIT(status, 1)
    }
на небольших наборах данных все ок. но на фетче 50тыс. записей вываливается с ошибкой. Что не так?
При этом сильно растет объем памяти, занимаемый приложением. Есть ли возможность фетча записей не вытягивая весь набор данных?

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Сообщение hvlad » 05 июн 2006, 16:50

isc_dsql_free_statement(.., DSQL_close) не достаточно, ещё нужен DSQL_drop

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 05 июн 2006, 16:56

При этом сильно растет объем памяти, занимаемый приложением.


если ты считываемые записи буферизируешь - разумеется будет расти.
Есть ли возможность фетча записей не вытягивая весь набор данных?
эээ...что??? фетч - это выборка ОДНОЙ записи. Никуда ее не складываешь - откуда возьмется расход памяти?

насчет arithmetic exception - это ты или данные кривые занес, или колупал структуру таблиц руками....

sunduk4
Сообщения: 18
Зарегистрирован: 02 май 2006, 13:45

Сообщение sunduk4 » 05 июн 2006, 17:10

isc_dsql_free_statement(.., DSQL_close) не достаточно, ещё нужен DSQL_drop
съедаемая память наполовину уменьшилась, но проблема осталась..
если ты считываемые записи буферизируешь - разумеется будет расти.
а как избавиться от буферизации записей? вся моя задача - данные из таблицы в файлик лить..
насчет arithmetic exception - это ты или данные кривые занес, или колупал структуру таблиц руками....
ни того ни другого не было. данные заливал скриптом, который ибэксперт сгенерил. после чего был сделан успешный бэкап-рестор базы.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 05 июн 2006, 17:19

а как избавиться от буферизации записей? вся моя задача - данные из таблицы в файлик лить..
так это ты в своем коде их буферизируешь. или нет?
кстати, malloc, вижу, а совобождается где?
потом, я смутно помню описание xsqlda, но что то не припомню, чтобы под sql_ind надо было память аллокировать...

sunduk4
Сообщения: 18
Зарегистрирован: 02 май 2006, 13:45

Сообщение sunduk4 » 05 июн 2006, 17:30

так это ты в своем коде их буферизируешь. или нет?
в коде данные из получаемой записи собираются в строку и пишутся в файл. строка - массив символов.
кстати, malloc, вижу, а совобождается где?
потом, я смутно помню описание xsqlda, но что то не припомню, чтобы под sql_ind надо было память аллокировать...
прошу прощения, после free_statement естественно делаю
free(main_sqlda)
судя по api guide, под нулл-индикатор надо выделять память..

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Сообщение hvlad » 06 июн 2006, 00:18

sunduk4 писал(а):
так это ты в своем коде их буферизируешь. или нет?
в коде данные из получаемой записи собираются в строку и пишутся в файл. строка - массив символов.
Строка растёт по мере необходимости ? Это грабли
sunduk4 писал(а):
кстати, malloc, вижу, а совобождается где?
потом, я смутно помню описание xsqlda, но что то не припомню, чтобы под sql_ind надо было память аллокировать...
прошу прощения, после free_statement естественно делаю
free(main_sqlda)
А все sqldata\sqlind освобождаются ?

sunduk4
Сообщения: 18
Зарегистрирован: 02 май 2006, 13:45

Сообщение sunduk4 » 06 июн 2006, 06:49

Строка растёт по мере необходимости ? Это грабли
строка - char result_str[64000];
после записи в файл каждой строчки - strcpy(result_str, "");
размер строчки нигде не изменяется в программе.
А все sqldata\sqlind освобождаются ?
хм.. вообще-то нет. а разве не достаточно после фетча освободить sqlda?
и sqlda\sqlind следует освобождать после каждой отфетченой строки либо после всего фетча?

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 06 июн 2006, 08:10

Во-первых, любые структуры надо освобождать когда они тебе больше не нужны. Кстати, DSQL_close достаточно если ты потом будешь хэндл использовать без повторного prepare.
Во-вторых, под SQL_VARYING надо выделять как минимум sqllen+sizeof(SHORT). Иначе - AV.
В-третьих, ты все же определись: в main_sqlda у тебя значения параметров или возвращаемых полей. Если первое - не суй ее в fetch. Если второе - в execute2. Кстати, нафига execute2? Простой execute надежнее.

sunduk4
Сообщения: 18
Зарегистрирован: 02 май 2006, 13:45

Сообщение sunduk4 » 06 июн 2006, 08:31

Во-первых, любые структуры надо освобождать когда они тебе больше не нужны. Кстати, DSQL_close достаточно если ты потом будешь хэндл использовать без повторного prepare.
с памятью разобрался - действительно, структуры освобождаю - приложение от силы до 8мб памяти использует.
Во-вторых, под SQL_VARYING надо выделять как минимум sqllen+sizeof(SHORT). Иначе - AV.
В-третьих, ты все же определись: в main_sqlda у тебя значения параметров или возвращаемых полей. Если первое - не суй ее в fetch. Если второе - в execute2. Кстати, нафига execute2? Простой execute надежнее.
под SQL_VARYING память выделяю так -
main_sqlda->sqlvar->sqldata = (char *)malloc(sizeof(char)*main_sqlda->sqlvar->sqllen + 1)

в main_sqlda у меня значения возвращаемых полей. переделал на execute все, убрал структуру из execute. Проблема осталась.
Ошибку получаю вот тут -

Код: Выделить всё

    if (main_fetch_stat != 100L) 
    { 
        ERREXIT(status, 1) 
    } 

sunduk4
Сообщения: 18
Зарегистрирован: 02 май 2006, 13:45

Сообщение sunduk4 » 06 июн 2006, 10:14

Всем спасибо! Разобрался.
Оказалось, что для одной из колонок память не совсем верно выделялась.

Ivan_Pisarevsky
Заслуженный разработчик
Сообщения: 644
Зарегистрирован: 15 фев 2005, 11:34

Сообщение Ivan_Pisarevsky » 06 июн 2006, 10:19

sunduk4 писал(а):
так это ты в своем коде их буферизируешь. или нет?
в коде данные из получаемой записи собираются в строку и пишутся в файл. строка - массив символов.
кстати, malloc, вижу, а совобождается где?
потом, я смутно помню описание xsqlda, но что то не припомню, чтобы под sql_ind надо было память аллокировать...
прошу прощения, после free_statement естественно делаю
free(main_sqlda)
судя по api guide, под нулл-индикатор надо выделять память..
Что мешает использовать экстернал тэйбл? инсерт ... селект тра-та-та, потом обычнам копированием забрал готовый файлик.

sunduk4
Сообщения: 18
Зарегистрирован: 02 май 2006, 13:45

Сообщение sunduk4 » 06 июн 2006, 10:26

Что мешает использовать экстернал тэйбл? инсерт ... селект тра-та-та, потом обычнам копированием забрал готовый файлик.
задача немного сложнее стоит. пытаюсь написать свой репликатор.

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 06 июн 2006, 10:55

sunduk4 писал(а):под SQL_VARYING память выделяю так -
main_sqlda->sqlvar->sqldata = (char *)malloc(sizeof(char)*main_sqlda->sqlvar->sqllen + 1)
Читай по губам: sqllen+sizeof(SHORT). sizeof(SHORT) == 2. Т.е. ты под буфер выделяешь на байт меньше чем требуется.

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 06 июн 2006, 10:56

sunduk4 писал(а):задача немного сложнее стоит. пытаюсь написать свой репликатор.
А чем готовые не устраивают? Я понимаю IBReplicator дорогой, но FBReplicator-то халява.

sunduk4
Сообщения: 18
Зарегистрирован: 02 май 2006, 13:45

Сообщение sunduk4 » 06 июн 2006, 11:45

Читай по губам: sqllen+sizeof(SHORT). sizeof(SHORT) == 2. Т.е. ты под буфер выделяешь на байт меньше чем требуется.
упс, точно...
А чем готовые не устраивают? Я понимаю IBReplicator дорогой, но FBReplicator-то халява.
к требованиям он не совсем подходит. -
1. связь между серверами оставляет желать лучшего, по-этому о прямом коннекте речь идти не может.
2. нужна репликация блоб-полей.
3. ОС - линукс

это минимум требований.

Ответить