Delphi TADOQuery.next пропуская запись

Описание заявки / обработки

Я поддерживаю старый код в Delphi XE. Приложение выполняет запрос к базе данных на удаленном сервере, а затем создает отчет на ПК. У нас был отчет об ошибке, что некоторые данные в одном из полей отсутствуют. Данное поле содержит огромное количество данных (несколько тысяч символов), собранных с сервера. Я не контролирую, какие данные собираются и хранятся в этом поле. Я обнаружил, что ошибка вызывается нулевыми значениями и другими управляющими символами (переводы строк и т. Д.), Встроенными в эти данные. Когда вызывался метод SaveToFile в TADOQuery, нулевые значения и другие управляющие символы приводили к тому, что любые последующие данные в поле игнорировались (SaveToFile в основном доходил до управляющих символов и прекращал чтение записи).

Решение этой ошибки заключалось в извлечении соответствующего поля из набора результатов, отфильтровывании любых управляющих символов и сохранении его во временном файле (на данный момент я не мог поместить его обратно в набор результатов, поскольку он находился в режиме чтения. только государство). Данные сохраняются в формате XML, поэтому я также должен сделать некоторые символы удобными для XML (как вы увидите в фрагменте кода). После вызова метода SaveToFile я считывал исправленные данные из временного файла и записывал их обратно в сохраненный отчет. Это многословно, но это работает.

Эта проблема

У меня сейчас новая проблема. Я замечаю, что в некоторых случаях в конце файла будет отсутствовать одна запись (рассматриваемое поле будет пустым). Я провел целую вечность, копаясь в проблеме, и она сводится к следующему коду (который используется для извлечения данных из поля перед вызовом SaveToFile). Код пропускает одну строку. Не каждый раз - примерно один из каждых двух или трех запусков запросов. Я знаю это для факта, потому что я добавил счетчик в цикл ниже при отладке и сравнил число выполнений цикла с количеством записей, и он возвращался на единицу меньше, когда произошла ошибка (в результате пустое поле), и равны, когда все данные появились в отчете. Никаких исключений не происходит, поэтому они не падают ни на что, а буквально пропускают запись.

assignfile(f, tempFilename);
rewrite(f);
adoqry.first;
repeat  
    try
        bytes := adoqry.fieldByName(fld).AsBytes;
        tmp := '';
        for i := 0 to length(bytes) - 1 do
            if bytes[i] < 32 then    // strip any control characters (nulls, line feeds etc.) from the string
                 tmp := tmp + ' '
            else
            begin
                 case char(bytes[i]) of
                      '&': tmp := tmp + '&amp;';
                      '''': tmp := tmp + '&apos;';
                      '"': tmp := tmp + '&quot;';
                      '>': tmp := tmp + '&gt;';
                      '<': tmp := tmp + '&lt;';
                 else
                      tmp := tmp + char(bytes[i]);
                 end;
            end;
        // when debugging, inc counter here to prove that the loop has been executed
        writeln(f, UTF8String(tmp));
        setLength(bytes, 0);
    except on e: exception do
        writeln(f, '');
    end;
    adoqry.next;
until adoqry.eof;
closefile(f);

Вопрос

Есть ли какая-то причина, по которой приведенный выше код пропустил бы запись (т.е. выполнял цикл только n - 1 раз, где n - количество записей)? Есть ли что-то, из-за чего вызов adoquery.next пропускает запись?

Изменить, чтобы уточнить вопросы, поднятые в комментариях

Данные отсутствуют в отчете. Это всегда одна запись, которая не обрабатывается. У меня в отчете более 20000 записей, а недостающая запись где-то посередине, но сузить ее сложно, так как данных так много. Поскольку пропускается одна запись, все после этой записи сдвигается вверх по записи (это означает, что большая часть отчета тогда неверна), а последняя запись содержит пустое поле.

1 ответ

Решение

Кажется, я наткнулся на решение этой проблемы. Я все еще тестирую, но, похоже, сейчас все исправлено.

Прежде чем я углубился в это, я отследил пропущенную запись. Есть ряд записей с одинаковыми данными в них. Я удалил запись, которая пропускалась, чтобы увидеть, что произойдет, и обработка пропустила другую запись (которая содержала те же данные). Как и прежде, он только пропускал его периодически (один раз в каждые два или три запуска запроса).

На "исправить"...

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

adoqry.executeOptions := [eoAsyncFetch];

Я закомментировал эту строку, и вдруг обработка работает нормально. Я выполнил несколько запросов, и все они возвращаются со всеми строками. Ничего не пропускается. Я продолжу тестировать, но кажется (на данный момент) все исправлено.

Другие вопросы по тегам