При разработке и сопровождении конфигураций на платформе 1С:Предприятие 7.7 разработчики периодически сталкиваются с ситуацией, когда при выполнении штатного «черного» запроса к регистру возникает исключительная ситуация: «Ошибка в индексном выражении». При этом ошибка может проявляться не постоянно, а лишь периодически, нарушая штатную работу пользователей.
Разберем детально механизм возникновения этой проблемы в файловой версии 1С 7.7, выясним ее технические предпосылки и рассмотрим эффективные способы устранения сбоя.
Рассмотрим структуру типового запроса, в котором проявляется проблема:
глТекстЗапроса = "
|Период с ДатаН По ДатаК; Без итогов;
|Заказ = Регистр.Заказы.Заказ;
|Номенклатура = Регистр.Заказы.Номенклатура;
|КолЗаказано = Регистр.Заказы.Заказано;
|КолПринято = Регистр.Заказы.Принято;
|Функция Заказано = Сумма(КолЗаказано);
|Функция НеПринято = Сумма(КолЗаказано-КолПринято);
|Группировка Номенклатура Без Групп;
|Условие(Заказ = ВыбЗаказ);
|Условие(Номенклатура = ВыбНоменклатура);
|";
Запрос.Выполнить(глТекстЗапроса);
Проанализируем техническую сторону выполнения такого кода:
Заказ имеет общий тип Документ (без указания конкретного вида), в таблицах формата DBF оно хранится в виде 13-символьной строки: 4 символа занимает идентификатор вида документа в 36-ричной системе счисления, а оставшиеся 9 символов — уникальный идентификатор конкретного документа. Если в условие Условие(Заказ = ВыбЗаказ) передается неинициализированная переменная, значение другого типа (число, строка, нетипизированное пустое значение), движок базы данных CodeBase не может составить корректное индексное выражение для временной таблицы, что приводит к фатальному сбою.Запрос платформа 1С 7.7 динамически создает во временном каталоге операционной системы (папка %TEMP%) временные таблицы DBF и соответствующие им индексы CDX. Если пути содержат длинные имена, спецсимволы, кириллицу или возникают коллизии блокировок при одновременном обращении нескольких процессов, попытка построения индекса завершается ошибкой.RGxxxx.cdx) или движений регистров (RAxxxx.cdx) вызывают сбой при обращении к измерениям, для которых включен отбор итогов или движений.Важное замечание: конструкция Попытка ... Исключение в платформе 1С 7.7 не способна перехватить критические ошибки ядра базы данных CodeBase, поэтому обернуть Запрос.Выполнить() в блок перехвата для скрытия сбоя не удастся — работа модуля будет прервана платформой.
Разберем по шагам, как защитить запрос от передачи некорректных параметров. Если в измерение могут попадать документы только определенных видов, исключим сравнение некорректных ссылок прямо в теле запроса.
Посмотрим на пример фильтрации по виду документа внутри текста запроса:
глТекстЗапроса = "
|Период с ДатаН По ДатаК; Без итогов;
|Заказ = Регистр.Заказы.Заказ;
|Номенклатура = Регистр.Заказы.Номенклатура;
|КолЗаказано = Регистр.Заказы.Заказано;
|КолПринято = Регистр.Заказы.Принято;
|Функция Заказано = Сумма(КолЗаказано);
|Функция НеПринято = Сумма(КолЗаказано-КолПринято);
|Группировка Номенклатура Без Групп;
|Условие(Найти(""ЗаказНаОтгрузку/ЗаказНаПриемку/"", Заказ.Вид() + ""/"") > 0);
|Условие(Заказ = ВыбЗаказ);
|Условие(Номенклатура = ВыбНоменклатура);
|";
Также перед запуском запроса обязательно выполним валидацию входных переменных:
Если (ТипЗначенияСтр(ВыбЗаказ) <> "Документ") Или (ПустоеЗначение(ВыбЗаказ) = 1) Тогда
// Прерываем выполнение до вызова метода Выполнить()
Возврат 0;
КонецЕсли;
Если (ТипЗначенияСтр(ВыбНоменклатура) <> "Справочник") Или (ПустоеЗначение(ВыбНоменклатура) = 1) Тогда
Возврат 0;
КонецЕсли;
Если глЗапрос.Выполнить(глТекстЗапроса) = 0 Тогда
Возврат 0;
КонецЕсли;
Штатная операция переиндексации при запуске конфигуратора не всегда исправляет логически поврежденную внутреннюю структуру файлов CDX. Для гарантированного восстановления индексов выполним следующие действия:
.CDX (таблицы данных .DBF не трогаем).Когда требуется быстро получить движения или остатки по конкретному набору измерений (в данном случае по известному заказу и номенклатуре), использование тяжелого объекта Запрос избыточно. Обращение через штатный объект Регистр работает быстрее и не создает временных DBF/CDX файлов в папке Temp.
Рассмотрим альтернативную реализацию через объектную модель:
Рег = СоздатьОбъект("Регистр.Заказы");
// Если в метаданных включен отбор движений по измерению
Рег.УстановитьЗначениеФильтра("Заказ", ВыбЗаказ);
Рег.УстановитьЗначениеФильтра("Номенклатура", ВыбНоменклатура);
ИтогЗаказано = 0;
ИтогНеПринято = 0;
Рег.ВыбратьДвижения(ДатаН, ДатаК);
Пока Рег.ПолучитьДвижение() = 1 Цикл
Если (Рег.Заказ = ВыбЗаказ) И (Рег.Номенклатура = ВыбНоменклатура) Тогда
ИтогЗаказано = ИтогЗаказано + Рег.Заказано;
ИтогНеПринято = ИтогНеПринято + (Рег.Заказано - Рег.Принято);
КонецЕсли;
КонецЦикла;
Поскольку генератор запросов 1С 7.7 активно использует системные переменные среды, проверим настройки путей на рабочем месте или сервере терминалов:
TEMP и TMP для пользователя и системы.C:\Temp.