Как исправить ошибку SDBL «Ожидается END» в динамическом списке 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки и поддержки конфигураций на платформе 1С:Предприятие 8.3 разработчики часто сталкиваются со специфическими ошибками внутреннего языка СУБД 1С — SDBL (Simple Data Base Language). Одной из наиболее неочевидных и труднодиагностируемых является ошибка: «Ошибка SDBL: Ожидается END», возникающая при открытии формы с динамическим списком.

Особенность этой проблемы заключается в том, что сам запрос динамического списка в конфигураторе выглядит абсолютно рабочим, успешно проходит проверку синтаксиса и без проблем открывается у большинства пользователей. Однако у одного конкретного сотрудника (или группы пользователей) при попытке войти в форму система выдает критический сбой. В этой статье мы подробно разберем, почему возникает данная ошибка, как оперативно вернуть пользователю работоспособность интерфейса и какие архитектурные подходы применить, чтобы полностью исключить появление этого сбоя в будущем.

Выясняем причину возникновения ошибки

Проанализируем техническую природу сбоя. Когда динамический список формирует запрос к базе данных, платформа 1С транслирует конфигурационный запрос на внутренний язык SDBL, который затем преобразуется в SQL-запрос, специфичный для используемой СУБД (например, PostgreSQL или MS SQL Server).

Если в динамическом списке присутствует поле составного типа данных (например, поле ДокументОснование, которое может принимать значения типов Документ.ПоступлениеТоваровУслуг, Документ.ЗаказПокупателя и т.д.), платформа генерирует сложные конструкции ветвления CASE WHEN... THEN... ELSE... END для каждого из возможных типов.

Ошибка SDBL возникает в тот момент, когда пользователь интерактивно через меню «Еще» — «Изменить форму» пытается вытащить «через точку» реквизит этого составного поля. Если запрашиваемый реквизит физически присутствует только у одного или нескольких типов из всего состава, но отсутствует у остальных, генератор SDBL пытается составить условное выражение. В старых или нестабильных релизах платформы (особенно часто это проявлялось на ветке 8.3.10 в связке с СУБД PostgreSQL) транслятор SDBL дает сбой: он некорректно закрывает синтаксическую структуру ветвления, буквально «теряя» ключевое слово END. СУБД возвращает ошибку синтаксиса, и платформа аварийно завершает работу с формой.

Рассмотрим по шагам все возможные способы решения данной проблемы — от быстрого «реанимационного» исправления до системных программных методов.

Решение 1. Очистка и сброс пользовательских настроек формы

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

Поскольку современное прикладное решение 1С чаще всего базируется на Библиотеке стандартных подсистем (БСП), выполним очистку настроек стандартными средствами:

  1. Откроем программу под пользователем с правами администратора.
  2. Перейдем в раздел Администрирование — Настройки пользователей и прав (или воспользуемся поиском по функциям и найдем обработку «Настройки пользователей»).
  3. Выберем проблемного пользователя в списке.
  4. Перейдем на вкладку «Настройки отчетов и форм» (в зависимости от версии БСП название вкладки может незначительно отличаться).
  5. В дереве настроек найдем нужную форму динамического списка, которая вызывает ошибку.
  6. Выделим ее и нажмем кнопку «Очистить».

Если поврежденная настройка мешает пользователю войти в саму систему или БСП не внедрена в конфигурацию, настройки можно удалить программно. Напишем и выполним в режиме предприятия небольшую обработку:


КлючОбъекта = "ОбщаяФорма.ФормаСписка/НастройкиФормы"; // Укажите путь к вашей форме
ПользовательИнформационнойБазы = ПользователиИнформационнойБазы.НайтиПоИмени("ИмяПроблемногоПользователя");
ХранилищеСистемныхНастроек.Удалить(КлючОбъекта, , ПользовательИнформационнойБазы.Имя);

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

Решение 2. Ограничение доступных полей на уровне схемы компоновки данных (СКД)

Чтобы предотвратить возможность выбора некорректных реквизитов составного типа пользователем, мы можем явно ограничить доступность полей «через точку» в конфигураторе.

Для этого откроем свойства динамического списка и перейдем в конструктор запроса. Мы можем использовать механизм фигурных скобок {}, который управляет доступными полями компоновки данных. Если мы не хотим, чтобы пользователь мог разыменовывать составное поле, мы можем явно перечислить разрешенные для выбора поля:


ВЫБРАТЬ
    Таблица.Ссылка КАК Ссылка,
    Таблица.ДокументОснование КАК ДокументОснование
{ВЫБРАТЬ
    Ссылка,
    ДокументОснование}
ИЗ
    Документ.РеализацияТоваровУслуг КАК Таблица

Также в настройках схемы компоновки данных (СКД), на которой базируется динамический список, на вкладке «Доступные поля» для составного реквизита рекомендуется снять флажки «Использовать в отборе», «Использовать в группировке» и «Использовать в порядке» для тех дочерних реквизитов, которые вызывают падение системы. Это исключит их появление в диалоговом окне «Изменить форму» у пользователя.

Решение 3. Явное приведение типов с помощью конструкции ВЫРАЗИТЬ

Если пользователю действительно жизненно необходимо видеть в динамическом списке конкретный реквизит одного из объектов составного типа, лучшей практикой 1С является явное приведение типов (типизация) в самом запросе списка.

Вместо того чтобы давать платформе возможность динамически определять типы, выполним жесткое связывание в тексте запроса с помощью функции ВЫРАЗИТЬ (CAST):


ВЫБРАТЬ
    Таблица.Ссылка КАК Ссылка,
    ВЫРАЗИТЬ(Таблица.ДокументОснование КАК Документ.ЗаказПокупателя).Номер КАК НомерЗаказа,
    ВЫРАЗИТЬ(Таблица.ДокументОснование КАК Документ.ЗаказПокупателя).Дата КАК ДатаЗаказа
ИЗ
    Документ.РеализацияТоваровУслуг КАК Таблица

При таком подходе платформа на уровне СУБД выполнит корректное левое соединение (LEFT JOIN) только с одной таблицей ЗаказПокупателя. Для всех остальных типов документов в поле ДокументОснование система вернет значение NULL, а SDBL-генератор построит синтаксически верную и оптимальную конструкцию запроса.

Решение 4. Вывод данных через событие ПриПолученииДанныхНаСервере

Обращение к реквизитам «через точку» от полей составного типа в динамических списках крайне негативно сказывается на производительности СУБД. Базе данных приходится соединять основную таблицу со всеми таблицами, входящими в составной тип, что порождает огромные запросы.

Для оптимизации и полного обхода ошибок SDBL мы можем получать текстовые представления или реквизиты составных типов динамически при выводе строк на экран с помощью обработчика события ПриПолученииДанныхНаСервере таблицы формы.

Проанализируем пример реализации этого метода:

  1. В динамическом списке получаем только саму ссылку на составной объект (без разыменования).
  2. Создаем на форме колонку (без привязки к данным пути динамического списка), например, НомерОснованияТекст.
  3. В модуле формы пишем обработчик события таблицы списка:

&НаСервере
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
    
    // Соберем все ссылки составного типа для пакетного запроса
    СписокОснований = Новый Массив;
    Для Каждого КлючИЗначение Из Строки Цикл
        ДанныеСтроки = КлючИЗначение.Значение.Данные;
        Если ЗначениеЗаполнено(ДанныеСтроки.ДокументОснование) Тогда
            СписокОснований.Добавить(ДанныеСтроки.ДокументОснование);
        КонецЕсли;
    КонецЦикла;
    
    Если СписокОснований.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    // Выполняем один быстрый точечный запрос к нужным типам данных
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    ЗаказПокупателя.Ссылка КАК Ссылка,
        |    ЗаказПокупателя.Номер КАК Номер
        |ИЗ
        |    Документ.ЗаказПокупателя КАК ЗаказПокупателя
        |ГДЕ
        |    ЗаказПокупателя.Ссылка В(&СписокОснований)";
    
    Запрос.УстановитьПараметр("СписокОснований", СписокОснований);
    РезультатЗапроса = Запрос.Выполнить().Выгрузить();
    
    // Заполняем текстовую колонку в оформлении строк
    Для Каждого КлючИЗначение Из Строки Цикл
        ДанныеСтроки = КлючИЗначение.Значение.Данные;
        ОформлениеСтроки = КлючИЗначение.Значение.Оформление;
        
        НайденнаяСтрока = РезультатЗапроса.Найти(ДанныеСтроки.ДокументОснование, "Ссылка");
        Если НайденнаяСтрока <> Неопределено Тогда
            ОформлениеСтроки.Ячейки.НомерОснованияТекст.УстановитьТекст(НайденнаяСтрока.Номер);
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

Этот метод гарантирует стопроцентную стабильность работы интерфейса, так как платформа вообще не использует динамический построитель SDBL для извлечения связанных данных составного типа.

Решение 5. Обновление технологической платформы

Поскольку поведение генератора SDBL, приводящее к пропуску ключевого слова END, официально признано ошибкой платформы (багом), кардинальным системным решением является обновление версии технологической платформы 1С:Предприятие.

Рекомендуется обновить платформу до актуальных релизов веток 8.3.15, 8.3.20 или выше. В новых версиях механизм трансляции условных конструкций SDBL в SQL-запросы СУБД PostgreSQL был полностью переработан. Платформа стала корректно обрабатывать ситуации с отсутствующими реквизитами у альтернативных типов данных и больше не падает с критической ошибкой.

← На главную