Поставили как-то перед кодером задачу - ограничить права доступа к некоторым организациям. В родной утэшке все есть: завел группы пользователей, раздал каждой по списку организаций, заполнил группы пользователей пользователями, включил константу и готово.
Но... По субъективным ощущениям (это которые без замеров) все стало чуть-чуть медленнее работать.
Кодер знал, что за кажущейся простотой ограничения доступа вроде
ОрганизацияВШапке("Организация")
скрывается подобный монстр-запрос:
##Если &ИспользоватьОграниченияПравДоступаНаУровнеЗаписей ##Тогда
ТекущаяТаблица ИЗ #ТекущаяТаблица КАК ТекущаяТаблица
ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ РАЗЛИЧНЫЕ
СоставГруппы.Ссылка КАК ГруппаПользователей
ИЗ
Справочник.ГруппыПользователей.ПользователиГруппы КАК СоставГруппы
ГДЕ
СоставГруппы.Пользователь = &ТекущийПользователь) КАК ГруппыПользователей
ПО (&ИспользоватьОграниченияПравДоступаНаУровнеЗаписей)
ГДЕ (&ИспользоватьОграниченияПравДоступаНаУровнеЗаписей = ЛОЖЬ
ИЛИ (НЕ 1 В
(ВЫБРАТЬ ПЕРВЫЕ 1
1 КАК ПолеОтбора
ИЗ
РегистрСведений.НазначениеВидовОбъектовДоступа КАК НазначениеВидовОбъектовДоступа
ГДЕ
НазначениеВидовОбъектовДоступа.ГруппаПользователей = ГруппыПользователей.ГруппаПользователей
И ВЫБОР
КОГДА НазначениеВидовОбъектовДоступа.ВидОбъектаДоступа = ЗНАЧЕНИЕ(Перечисление.ВидыОбъектовДоступа.Организации)
И ТекущаяТаблица.#Параметр(1) ССЫЛКА Справочник.Организации
И НЕ ТекущаяТаблица.#Параметр(1) = ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка)
ТОГДА ВЫБОР
КОГДА 1 В
(ВЫБРАТЬ ПЕРВЫЕ 1
1
ИЗ
(ВЫБРАТЬ
1 КАК ПолеОтбора
) КАК Оптмизация ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НастройкиПравДоступаПользователей КАК НастройкиПравДоступаПользователей
ПО
НастройкиПравДоступаПользователей.ОбъектДоступа = ТекущаяТаблица.#Параметр(1)
И НастройкиПравДоступаПользователей.ВидОбъектаДоступа = ЗНАЧЕНИЕ(Перечисление.ВидыОбъектовДоступа.Организации)
И (НастройкиПравДоступаПользователей.Пользователь = НазначениеВидовОбъектовДоступа.ГруппаПользователей
ИЛИ НастройкиПравДоступаПользователей.Пользователь = ЗНАЧЕНИЕ(Справочник.ГруппыПользователей.ВсеПользователи)))
ТОГДА ИСТИНА
ИНАЧЕ ЛОЖЬ
КОНЕЦ
ИНАЧЕ ИСТИНА
КОНЕЦ = ЛОЖЬ))
И НЕ ГруппыПользователей.ГруппаПользователей ЕСТЬ NULL)
##КонецЕсли
От такого все что угодно можно ожидать, подумал кодер и решил придумать способ оптимизации.
"Сформировать бы перед запуском системы список доступных организаций, да и передать в шаблон ограничений, чтобы запрос был как можно меньше", рассуждал кодер, и стал искать способы. Создавать регистр сведений - масло масляное, передавать таблицу значений нельзя, список значений тоже, и массив нельзя... Ага, а фиксированный массив можно. Сказано - сделано. Перед началом работы системы был вставлен следующий код:
Если НЕ РольДоступна("ПолныеПрава") Тогда
Если Константы.ИспользоватьОграниченияПравДоступаНаУровнеЗаписей.Получить() Тогда
Запрос = Новый Запрос("ВЫБРАТЬ
| ГруппыПользователейПользователиГруппы.Ссылка
|ПОМЕСТИТЬ ВТ_ГП
|ИЗ
| Справочник.ГруппыПользователей.ПользователиГруппы КАК ГруппыПользователейПользователиГруппы
|ГДЕ
| ГруппыПользователейПользователиГруппы.Пользователь = &Пользователь
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗРЕШЕННЫЕ
| &Пользователь КАК Пользователь,
| НастройкиПравДоступаПользователей.ОбъектДоступа КАК Организация,
| НастройкиПравДоступаПользователей.Запись,
| НастройкиПравДоступаПользователей.Отчеты
|ПОМЕСТИТЬ ВТ_Доступ
|ИЗ
| РегистрСведений.НастройкиПравДоступаПользователей КАК НастройкиПравДоступаПользователей
|ГДЕ
| НастройкиПравДоступаПользователей.Пользователь В
| (ВЫБРАТЬ
| ВТ_ГП.Ссылка
| ИЗ
| ВТ_ГП КАК ВТ_ГП)
| КОНЕЦ
|
|СГРУППИРОВАТЬ ПО
| НастройкиПравДоступаПользователей.ОбъектДоступа,
| НастройкиПравДоступаПользователей.Запись
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_Доступ.Пользователь,
| ВТ_Доступ.Организация
|ИЗ
| ВТ_Доступ КАК ВТ_Доступ
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_Доступ.Пользователь,
| ВТ_Доступ.Организация
|ИЗ
| ВТ_Доступ КАК ВТ_Доступ
|ГДЕ
| ВТ_Доступ.Запись");
ТекущийПользователь = ПараметрыСеанса.ТекущийПользователь;
Запрос.УстановитьПараметр("Пользователь", ТекущийПользователь);
МассивРезультатов = Запрос.ВыполнитьПакет();
РезультатЗапросаЧтение = МассивРезультатов[2].Выгрузить();
РезультатЗапросаЗапись = МассивРезультатов[3].Выгрузить();
МассивОрганизацийДоступныхДляЧтения = РезультатЗапросаЧтение.ВыгрузитьКолонку("Организация");
ПараметрыСеанса.СписокОрганизацийДоступныхДляЧтения = Новый ФиксированныйМассив(МассивОрганизацийДоступныхДляЧтения);
МассивОрганизацийДоступныхДляЗаписи = РезультатЗапросаЗапись.ВыгрузитьКолонку("Организация");
ПараметрыСеанса.СписокОрганизацийДоступныхДляЗаписи = Новый ФиксированныйМассив(МассивОрганизацийДоступныхДляЗаписи);
КонецЕсли;
КонецЕсли;
И монстр-запрос для чтения превратился во вполне компактный:
##Если &ИспользоватьОграниченияПравДоступаНаУровнеЗаписей ##Тогда
ТекущаяТаблица ИЗ #ТекущаяТаблица КАК ТекущаяТаблица
ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
1 КАК Поле1) КАК РазрешениеДоступа
ПО (&ИспользоватьОграниченияПравДоступаНаУровнеЗаписей)
ГДЕ
(ТекущаяТаблица.#Параметр(1) В (&СписокОрганизацийДоступныхДляЧтения)
ИЛИ ТекущаяТаблица.#Параметр(1) = ЗНАЧЕНИЕ(Справочник.Организации.))
##КонецЕсли
Для записи аналогично, только подставить другой параметр сеанса.
Также были изменены и остальные запросы в шаблонах ограничений доступа, на том и закончился очередной рабочий день.
Наступило утро. Обычные пользователи без полных прав вошли в программу и стали работать как обычно.
Пользователи же с полными правами стали натыкаться в разных местах на непонятное сообщение: "Попытка получить неинициализированное значение параметра сеанса".
Анализ ситуации показал, что приведенный код выполнял инициализацию параметров сеанса только для неполноправных пользователей.
Да, но в полных правах нет никаких шаблонов ограничений, им все доступно, причем здесь неинициализированные параметры сеанса, размышлял кодер...
Система была давняя, кодер - не первый ее доработчик и исследователь, и на наборы ролей пользователей особого внимания не обращал.
А зря. У пользователей с полными правами, (наверное для большей полноты прав) были добавлены еще по нескольку ролей, эти роли и пытались получить список доступных организаций через неинициализированный параметр сеанса.
Попытка снять "лишние" роли привела к отключению у полноправных пользователей некоторых возможностей. Это, в свою очередь, произошло от того, что часть из этих "лишних" ролей использовалась только в коде для включения определенного функционала (речь идет об УТ 10.3, функциональные опции еще только снятся), но поскольку роли были скопированы с типовых ролей, то и потянули за собой и шаблоны ограничений доступа, и ограничения доступа к метаданным.
Финал оптимистичный, в стиле анекдота про отца-программиста и сына: "Знаешь что, сынок! Не трогай-ка ты работающую систему!" - наборы ролей пользователей были восстановлены в прежнем состоянии, над условием "Если не РольДоступна("ПолныеПрава")..." появилась пара строк инициализации параметров сеанса пустыми фиксированными массивами и все продолжили спокойно работать до следущего внедрения...