При проектировании систем прав доступа на уровне записей (Record Level Security, или RLS) разработчики часто сталкиваются со странным или неочевидным поведением запросов. Одной из таких загадок является появление конструкции ИЛИ NULL в ограничениях доступа. На первый взгляд это выглядит как синтаксическая ошибка или неаккуратность, но за этим скрываются важные архитектурные особенности работы платформы «1С:Предприятие» и СУБД.
Рассмотрим подробнее, почему возникает такая ситуация, как ее обрабатывают базы данных и как правильно реализовать ограничение доступа, если вам необходимо учесть пустые значения.
Представим ситуацию: в одной из ролей самописной конфигурации было обнаружено следующее условие ограничения доступа на чтение документа (секция «Прочие поля»):
ГДЕ Пользователь В (&Пользователи) ИЛИ NULL
Здесь Пользователь — это общий реквизит или обычный реквизит документа со ссылкой на справочник пользователей, а &Пользователи — параметр сеанса, содержащий фиксированный массив разрешенных пользователей. Возникает логичный вопрос: зачем в конце добавлено ИЛИ NULL? Позволяет ли это прочитать документы с незаполненными авторами, или это просто бесполезный «мусорный» код?
Чтобы понять, как данное выражение обрабатывается СУБД, нам необходимо обратиться к понятию трехзначной логики (3VL — Three-Valued Logic), которая используется в современных реляционных базах данных (MS SQL Server, PostgreSQL, IBM DB2).
В отличие от классической булевой логики, где выражение может быть только истинным или ложным, в базах данных любое логическое сравнение с участием NULL может вернуть три состояния: ИСТИНА (True), ЛОЖЬ (False) или НЕИЗВЕСТНО (Unknown/NULL). Оператор ИЛИ (OR) при взаимодействии с NULL вычисляется по следующим правилам:
WHERE (в 1С это ГДЕ) трактует результат NULL как ложь. Соответственно, если пользователь не входит в массив, доступ к документу будет закрыт.Таким образом, добавление конструкции ИЛИ NULL абсолютно ни на что не влияет. Оно никогда не сможет сделать ложное условие истинным. В секции ГДЕ эта конструкция ведет себя точно так же, как обычное ИЛИ ЛОЖЬ. Сравнение NULL = NULL или просто логический литерал NULL без операторов проверки никогда не вернут истину.
Если данное условие математически бесполезно, выясним причины его появления в реальных конфигурациях 1С. Как правило, это связано со следующими факторами:
ГДЕ Пользователь В (&Пользователи) [ДополнительноеУсловие]
Если при формировании прав выясняется, что дополнительное условие не требуется, алгоритм заменяет заглушку на нейтральное значение. Если вместо пустой строки или конструкции ИЛИ ИСТИНА по ошибке подставляется ИЛИ NULL, запрос приобретает именно такой некорректный вид.
NULL.ИЛИ Пользователь ЕСТЬ NULL), но поспешил или отвлекся, оставив незавершенную конструкцию, которая тем не менее успешно прошла синтаксический контроль платформы.С технической точки зрения наличие «мусорного» кода в RLS-запросах нежелательно, однако современные СУБД легко справляются с этой проблемой:
OR NULL, поэтому физического замедления работы базы данных не происходит.Если изначальная задумка автора RLS действительно состояла в том, чтобы разрешить пользователям просматривать документы, у которых реквизит Пользователь не заполнен, то текущий запрос эту задачу не решал. Нам нужно переписать его правильно.
В платформе 1С пустые значения могут храниться по-разному в зависимости от типа данных реквизита:
Если реквизит Пользователь ссылается на справочник (например, СправочникСсылка.Пользователи), то в базе данных незаполненное значение хранится как пустая ссылка, а не как NULL. Нам нужно явно проверить реквизит на равенство пустой ссылке:
ГДЕ Пользователь В (&Пользователи)
ИЛИ Пользователь = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)
Если ограничение RLS строится через левое соединение с другой таблицей, и искомое поле действительно может физически отсутствовать в результирующей выборке, только тогда в запросе появится настоящий NULL. Для его проверки мы должны использовать строго оператор ЕСТЬ NULL:
ГДЕ Пользователь В (&Пользователи)
ИЛИ Пользователь ЕСТЬ NULL
Проанализировав логику работы СУБД и платформы, мы можем сделать вывод: встретив конструкцию ИЛИ NULL в ограничениях доступа, ее можно и нужно смело удалять из кода, предварительно убедившись, что под ней не скрывалась попытка проверить поле на пустую ссылку или использовать оператор ЕСТЬ NULL.