ADO.OLEDB.JET - Access Violation при передаче неполного параметра
Проблема обнаружена под операционной системой windows 2000 sp3, в среде
delphi6, delphi7 (скорее всего не зависит от версии delphi) с использованием
microsoft jet db engine версия 4, sp3. Некоторый, вполне типичный, код
заполнения запроса в процессе выполнения вызывает access violation, притом, что
согласно документации все должно работать корректно.
Пример кода:
Допустим, есть база данных в ms access 2000, имеющая таблицу main и в ней
целочисленное (int) поле id в качестве главного ключа. Так же есть компонент
adoquery1: tadoquery, для доступа к базе данных. Максимальное значение поля id
может быть получено следующим кодом:
Как было показано в комментарии, исключение возникает в процессе добавления
текста в запрос, но при этом в сообщении об ошибке указывалось, что исключение
произошло внутри библиотеки jet.
Исследование исходных текстов компонента tadoquery показало следущее: свойство
sql, типа tstrings связано с полем fsql: tstrings, создаваемого как экземляр
класса tstringlist, при этом объекту fsql назначается обработчик события
onchange — метод querychanged (protected, статический), что исключает его
возможную перегрузку.
Этот метод устанавливает свойство active в false и присваивает содержимое
fsql.text полю commandtext объекта ado.
За отсутствием исходных текстов библиотеки jet, дальнейшее исследование пришлось
прекратить, но можно сделать несколько выводов:
Корни проблемы в невполне корректном поведении как кода от borland, так и от
microsoft. Компонент tadoquery передает в ado неоконченный sql-запрос, а jet
начинает анализировать этот запрос до того, как он полностью поступит. Возможно,
microsoft пытался реализовать упреждающее выполнение запросов, чтобы снизить
время обработки запроса после получения команды на выполнение.
Теоретически и другие драйвера баз данных могут быть чувствительны к неполным
запросам, так что данная ошибка может появляться и при работе с другими СУБД.
При дополнительном исследовании были выяснены интересные подробности:
Данный код не прерывает выполнения при возникновении exception, т.е.
теоретически даже try..except не нужен. Похоже, это происходит из-за того, что
jet является com-объектом, а их методы вызываются как safecall. Дальнейшие тесты
подтвердили это предположение — при снятии галочки stop on delphi exceptions и в
варианте exe-файла ошибка не проявлялась. Таким образом, ситуация несколько
меняется — исключение возникает только в среде разработки, что, правда, является
слабым утешением, т.к. многие програмисты работают с настройками по-умолчанию, и
в случае его возникновения могут долго ломать голову, ища свою ошибку там где ее
нет.
ТИПОВЫЕ РЕШЕНИЯ
1. Передавать запрос целиком — одной строкой. Пример:
adoquery1.active := false;
adoquery1.sql.text := 'select max(id) as idmax from main;';
adoquery1.active := true;
2. Отключить галочку tools->debugger options->language exceptions->stop
on delphi exceptions
3. Просто игнорировать это исключение (в этом случае в процессе разработки
придется периодически несколько раз нажимать ok, что, конечно, менее удобно)
Напоследок: Небольшое исследование исходного кода компонент данных bde и
dbexpress показало, что в них передача sql-запроса происходит через
промежуточное текстовое поле, что, на мой взгляд, исключает в них возможность
появления аналогичной ошибки.
КОММЕНТАРИЙ:
Компонент tadoquery от delphi 5 содержит аналогичный код (метод querychanged),
приводящий к ошибке.
Еще один вариант решения - использовать стандартные возможности tstrings по
управлению обновлением:
При разработке CMS S.Builder наша команда
активно использовала AJAX. Теперь вот решили поделиться накопленным
опытом. Начнем с этого хабратопика. Не буду здесь затрагивать различные
фреймворки и библиотеки. Свой код всегда роднее. Для работы с AJAX-ом в
S.Builder написана библиотека
sbAJAX. Можете качать и пользоваться :). В этом файле есть функция
sbEvalJS. Для тех, кто не знает, объясню. При подгрузке через AJAX и вставке
на страницу HTML-кода, содержащего JavaScript, JavaScript выполняться не будет
или полезут баги. Эта функция как раз решает поставленную задачу.
Хотя наш обзор немного запоздал, оригинальный Dojo 1.2 вышел в релизной
версии ещё 6-го октября, но сейчас мы наверстаем упущенное. И так, Dojo Toolkit — это самая мощная и
гибкая ajax-библиотека из всех, что есть на рынке, она активно развивается и
имеет большое комьюнити. Кстати, это самое комьюнити, совместно с компанией
Sitepen, имеет ещё несколько проектов, среди которых и Cometd и некоторые
другие, не менее интересные, о которых мы скоро вам расскажем. Сегодня же все
внимание на флагманский продукт —
Dojo
1.2.
Если вы профессиональный веб-разработчик и постоянно имеете дело с
разработкой и отладкой сложных AJAX приложений, то наверняка знаете и
используете Firebug — плагин для браузера
Firefox, предназначенный для отладки и исследования веб-приложений. Текущая его
версия, 1.2х достаточно стабильная и функциональна, чтобы помочь в 99% проблем,
которые могут возникнуть при разработке. Но и этот инструмент не лишён если не
недостатков, то некоторых фич, которые могли бы облегчить работу. И даже
идеальный инструмент можно сделать ещё более идеальным, как бы это не звучало.