Пятница, 24.10.2025, 04:04
Приветствую Вас Гость | RSS
Главная | Статьи | Регистрация | Вход
Меню сайта
Категории раздела
Базы данных [11]
Мультимедиа [2]
Графика [2]
Защита [0]
Математика [0]
Сеть-интернет [1]
Система [4]
Разное [4]
Поиск
Вход на сайт
Наш опрос
Оцените мой сайт
Всего ответов: 7
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Мой сайт
Главная » Статьи » Базы данных [ Добавить статью ]

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 может быть получено следующим кодом:

adoquery1.active := false;
adoquery1.sql.clear;
adoquery1.sql.add('select max(id)'); // -- Сбой здесь !!!
adoquery1.sql.add('as idmax');
adoquery1.sql.add('from main');
adoquery1.active := true;
Как было показано в комментарии, исключение возникает в процессе добавления текста в запрос, но при этом в сообщении об ошибке указывалось, что исключение произошло внутри библиотеки 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 по управлению обновлением:

adoquery1.sql.beginupdate;
try
adoquery1.sql.clear;
adoquery1.sql.add('select max(id)');
adoquery1.sql.add('as idmax');
adoquery1.sql.add('from main');
finally
adoquery1.sql.endupdate;
end;
В этом случае событие onchange произойдет только при выполнении endupdate.



Источник: http://delphisources.at.ua/publ/bazy_dannykh/ado/ado_oledb_jet_access_violation_pri_peredache_nepolnogo_parametra/32-1-0
Категория: Базы данных | Добавил: maxim-pogasim (03.09.2015)
Просмотров: 212 | Теги: Access | Рейтинг: 0.0/0
Всего комментариев: 0
avatar
Программистами не рождаются.Copyright BPC Team © 2014 - 2025

Хочу сжечь на костре этот дебильный Хостинг от uCozЯндекс.Метрика