Files
2022-10-05 22:39:00 +03:00

9449 lines
676 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2022, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////
#Область СлужебныйПрограммныйИнтерфейс
// Проверить необходимость обновления неразделенных данных информационной базы
// при смене версии конфигурации.
//
Функция НеобходимоОбновлениеНеразделенныхДанныхИнформационнойБазы() Экспорт
УстановитьПривилегированныйРежим(Истина);
Если ОбщегоНазначения.РазделениеВключено() Тогда
ВерсияМетаданных = Метаданные.Версия;
Если ПустаяСтрока(ВерсияМетаданных) Тогда
ВерсияМетаданных = "0.0.0.0";
КонецЕсли;
ВерсияОбщихДанных = ВерсияИБ(Метаданные.Имя, Истина);
Если НеобходимоВыполнитьОбновление(ВерсияМетаданных, ВерсияОбщихДанных) Тогда
Возврат Истина;
КонецЕсли;
Если НЕ ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
УстановитьПривилегированныйРежим(Истина);
Запустить = ПараметрыСеанса.ПараметрыКлиентаНаСервере.Получить("ЗапуститьОбновлениеИнформационнойБазы");
УстановитьПривилегированныйРежим(Ложь);
Если Запустить <> Неопределено И ЕстьПраваНаОбновлениеИнформационнойБазы() Тогда
Возврат Истина;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Возврат Ложь;
КонецФункции
// Выполнить неинтерактивное обновление данных ИБ.
//
// Параметры:
//
// ПараметрыОбновления - Структура:
// * ИсключениеПриНевозможностиБлокировкиИБ - Булево - если Ложь, тогда при неудачной
// попытке установки монопольного режима исключение не вызывается,
// а возвращается строка "ОшибкаУстановкиМонопольногоРежима".
//
// * ПриЗапускеКлиентскогоПриложения - Булево - начальное значение Ложь. Если указать Истина,
// тогда параметры работы программы не будут обновляться, т.к. при клиентском
// запуске они обновляются в самом начале (до авторизации пользователи и обновления ИБ).
// Параметр требуется для оптимизации клиентского режима запуска, чтобы не выполнять
// обновление параметров работы программы дважды.
// При внешнем вызове, например, в сеансе внешнего соединения, параметры работы
// программы должны быть обновлены до продолжения обновления ИБ.
// * Перезапустить - Булево - возвращаемое значение. Требование перезапуска,
// в некоторых случаях ПриЗапускеКлиентскогоПриложения, например,
// при возврате к конфигурации базы данных подчиненного узла РИБ,
// см. общий модуль ОбменДаннымиСервер процедуру.
// ВыполнитьСинхронизациюПриОтсутствииОбновленияИнформационнойБазы.
// * УстановленнаяБлокировкаИБ - см. БлокировкаИБ
// * ВФоне - Булево - если обновление информационной базы выполняется
// в фоне, то следует передавать Истина, иначе Ложь.
// * ВыполнятьОтложенныеОбработчики - Булево - если Истина, отложенное обновление будет выполнено
// в основном цикле обновления. Только для клиент-серверного режима работы.
//
// Возвращаемое значение:
// Строка - признак выполнения обработчиков обновления:
// "Успешно", "НеТребуется", "ОшибкаУстановкиМонопольногоРежима".
//
Функция ВыполнитьОбновлениеИнформационнойБазы(ПараметрыОбновления) Экспорт
ДополнительныеПараметры = ДействияПередОбновлениемИнформационнойБазы(ПараметрыОбновления);
Если ЗначениеЗаполнено(ДополнительныеПараметры.Возврат) Тогда
Возврат ДополнительныеПараметры.Возврат;
КонецЕсли;
ПараметрЗапускаКлиента = ПараметрыСеанса.ПараметрыКлиентаНаСервере.Получить("ПараметрЗапуска");
ОтладкаОтложенногоОбновления = СтрНайти(НРег(ПараметрЗапускаКлиента), НРег("ОтладкаОтложенногоОбновления")) > 0;
РежимВыполненияОтложенногоОбновления = РежимВыполненияОтложенногоОбновления(ПараметрыОбновления);
ВыполнитьОтложенноеОбновлениеСейчас = Не ОтладкаОтложенногоОбновления И РежимВыполненияОтложенногоОбновления = "Монопольно";
ДополнительныеПараметры.Вставить("ВыполнитьОтложенноеОбновлениеСейчас", ВыполнитьОтложенноеОбновлениеСейчас);
ДополнительныеПараметры.Вставить("РежимВыполненияОтложенногоОбновления", РежимВыполненияОтложенногоОбновления);
ВыполнитьДействияПриОбновленииИнформационнойБазы(ПараметрыОбновления, ДополнительныеПараметры);
ВыполнитьДействияПослеОбновленияИнформационнойБазы(ПараметрыОбновления, ДополнительныеПараметры);
Возврат "Успешно";
КонецФункции
// Получить версию конфигурации или родительской конфигурации (библиотеки),
// которая хранится в информационной базе.
//
// Параметры:
// ИдентификаторБиблиотеки - Строка - имя конфигурации или идентификатор библиотеки.
// ПолучитьВерсиюОбщихДанных - Булево - если указать Истина, то при работе в модели сервиса будет
// возвращена версия в общих данных.
//
// Возвращаемое значение:
// Строка - версия.
//
// Пример использования:
// ВерсияКонфигурацииИБ = ВерсияИБ(Метаданные.Имя);
//
Функция ВерсияИБ(Знач ИдентификаторБиблиотеки, Знач ПолучитьВерсиюОбщихДанных = Ложь) Экспорт
УстановитьОтключениеБезопасногоРежима(Истина);
УстановитьПривилегированныйРежим(Истина);
СтандартнаяОбработка = Истина;
Результат = "";
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.ПриОпределенииВерсииИБ(ИдентификаторБиблиотеки, ПолучитьВерсиюОбщихДанных,
СтандартнаяОбработка, Результат);
КонецЕсли;
Если СтандартнаяОбработка Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВерсииПодсистем.Версия
|ИЗ
| РегистрСведений.ВерсииПодсистем КАК ВерсииПодсистем
|ГДЕ
| ВерсииПодсистем.ИмяПодсистемы = &ИмяПодсистемы";
Запрос.УстановитьПараметр("ИмяПодсистемы", ИдентификаторБиблиотеки);
ТаблицаЗначений = Запрос.Выполнить().Выгрузить();
Результат = "";
Если ТаблицаЗначений.Количество() > 0 Тогда
Результат = СокрЛП(ТаблицаЗначений[0].Версия);
КонецЕсли;
КонецЕсли;
Возврат ?(ПустаяСтрока(Результат), "0.0.0.0", Результат);
КонецФункции
// Записывает в информационную базу версию конфигурации или родительской конфигурации (библиотеки).
//
// Параметры:
// ИдентификаторБиблиотеки - Строка - имя конфигурации или родительской конфигурации (библиотеки),
// НомерВерсии - Строка - номер версии.
// ЭтоОсновнаяКонфигурация - Булево - признак, что ИдентификаторБиблиотеки соответствует имени конфигурации.
// ВыполненаРегистрация - Булево - признак, что выполнена регистрация данных для отложенного обновления.
//
Процедура УстановитьВерсиюИБ(Знач ИдентификаторБиблиотеки, Знач НомерВерсии, Знач ЭтоОсновнаяКонфигурация, ВыполненаРегистрация = Неопределено) Экспорт
СтандартнаяОбработка = Истина;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.ПриУстановкеВерсииИБ(ИдентификаторБиблиотеки, НомерВерсии, СтандартнаяОбработка, ЭтоОсновнаяКонфигурация);
КонецЕсли;
Если Не СтандартнаяОбработка Тогда
Возврат;
КонецЕсли;
НаборЗаписей = РегистрыСведений.ВерсииПодсистем.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ИмяПодсистемы.Установить(ИдентификаторБиблиотеки);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.ИмяПодсистемы = ИдентификаторБиблиотеки;
НоваяЗапись.Версия = НомерВерсии;
НоваяЗапись.ЭтоОсновнаяКонфигурация = ЭтоОсновнаяКонфигурация;
Если ВыполненаРегистрация <> Неопределено Тогда
НоваяЗапись.ВыполненаРегистрацияОтложенныхОбработчиков = ВыполненаРегистрация;
КонецЕсли;
НаборЗаписей.Записать();
КонецПроцедуры
// Записывает информацию о результате регистрации отложенных обработчиков на плане обмена.
//
Процедура ОтметитьРегистрациюОтложенныхОбработчиковОбновления(ИмяПодсистемы = Неопределено, Значение = Истина) Экспорт
СтандартнаяОбработка = Истина;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.ПриОтметкеРегистрацииОтложенныхОбработчиковОбновления(ИмяПодсистемы, Значение, СтандартнаяОбработка);
КонецЕсли;
Если Не СтандартнаяОбработка Тогда
Возврат;
КонецЕсли;
НаборЗаписей = РегистрыСведений.ВерсииПодсистем.СоздатьНаборЗаписей();
Если ИмяПодсистемы <> Неопределено Тогда
НаборЗаписей.Отбор.ИмяПодсистемы.Установить(ИмяПодсистемы);
КонецЕсли;
НаборЗаписей.Прочитать();
Если НаборЗаписей.Количество() = 0 Тогда
Возврат;
КонецЕсли;
Для Каждого ЗаписьРегистра Из НаборЗаписей Цикл
ЗаписьРегистра.ВыполненаРегистрацияОтложенныхОбработчиков = Значение;
КонецЦикла;
НаборЗаписей.Записать();
КонецПроцедуры
// Возвращает режим обновления данных информационной базы.
// Допускается вызывать только до начала обновления информационной базы (иначе возвращает "ОбновлениеВерсии").
//
// Возвращаемое значение:
// Строка - "НачальноеЗаполнение", если это первый запуск пустой базы (области данных);
// "ОбновлениеВерсии", если выполняется первый запуск после обновление конфигурации базы данных;
// "ПереходСДругойПрограммы", если выполняется первый запуск после обновление конфигурации базы данных,
// в которой изменилось имя основной конфигурации.
//
Функция РежимОбновленияДанных() Экспорт
УстановитьПривилегированныйРежим(Истина);
СтандартнаяОбработка = Истина;
РежимОбновленияДанных = "";
ИмяОсновнойКонфигурации = Метаданные.Имя;
ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем();
Для каждого ИмяПодсистемы Из ОписанияПодсистем.Порядок Цикл
ОписаниеПодсистемы = ОписанияПодсистем.ПоИменам.Получить(ИмяПодсистемы); // см. СтандартныеПодсистемыПовтИсп.НовоеОписаниеПодсистемы
Если НЕ ЗначениеЗаполнено(ОписаниеПодсистемы.ОсновнойСерверныйМодуль) Тогда
Продолжить;
КонецЕсли;
Если ОписаниеПодсистемы.Имя <> ИмяОсновнойКонфигурации Тогда
Продолжить;
КонецЕсли;
Модуль = ОбщегоНазначения.ОбщийМодуль(ОписаниеПодсистемы.ОсновнойСерверныйМодуль);
Модуль.ПриОпределенииРежимаОбновленияДанных(РежимОбновленияДанных, СтандартнаяОбработка);
КонецЦикла;
Если НЕ СтандартнаяОбработка Тогда
ОбщегоНазначенияКлиентСервер.ПроверитьПараметр("ПриОпределенииРежимаОбновленияДанных", "РежимОбновленияДанных",
РежимОбновленияДанных, Тип("Строка"));
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Недопустимое значение параметра %1 в %2.
|Ожидалось: %3, %4 или %5; передано значение: %6 (тип %7).'"),
"РежимОбновленияДанных", "ПриОпределенииРежимаОбновленияДанных",
"НачальноеЗаполнение", "ОбновлениеВерсии", "ПереходСДругойПрограммы",
РежимОбновленияДанных, ТипЗнч(РежимОбновленияДанных));
ОбщегоНазначенияКлиентСервер.Проверить(РежимОбновленияДанных = "НачальноеЗаполнение"
Или РежимОбновленияДанных = "ОбновлениеВерсии" Или РежимОбновленияДанных = "ПереходСДругойПрограммы", Сообщение);
Возврат РежимОбновленияДанных;
КонецЕсли;
Результат = Неопределено;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.ПриОпределенииРежимаОбновленияОбластиДанных(СтандартнаяОбработка, Результат);
КонецЕсли;
Если НЕ СтандартнаяОбработка Тогда
Возврат Результат;
КонецЕсли;
Возврат РежимОбновленияДанныхВЛокальномРежимеРаботы();
КонецФункции
// Для внутреннего использования.
Функция ПараметрыОтбораОбработчиков() Экспорт
Результат = Новый Структура;
Результат.Вставить("ПолучатьРазделенные", Ложь);
Результат.Вставить("РежимОбновления", "Монопольно");
Результат.Вставить("УчитыватьПервыйОбменВРИБ", Ложь);
Результат.Вставить("ПервыйОбменВРИБ", Ложь);
Возврат Результат;
КонецФункции
Функция ОбработчикиОбновленияВИнтервале(Знач ИсходнаяТаблицаОбработчиков, Знач ВерсияОт, Знач ВерсияДо,
Знач ПараметрыОтбораОбработчиков = Неопределено) Экспорт
ПараметрыОтбора = ПараметрыОтбораОбработчиков;
Если ПараметрыОтбора = Неопределено Тогда
ПараметрыОтбора = ПараметрыОтбораОбработчиков();
КонецЕсли;
// Добавление номера в таблицу, для упорядочивания в порядке добавления.
ВсеОбработчики = ИсходнаяТаблицаОбработчиков.Скопировать();
ВсеОбработчики.Колонки.Добавить("НомерПоПорядку", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(10, 0)));
Для Индекс = 0 По ВсеОбработчики.Количество() - 1 Цикл
СтрокаОбработчика = ВсеОбработчики[Индекс];
СтрокаОбработчика.НомерПоПорядку = Индекс + 1;
КонецЦикла;
ОтметитьОбработчикиНовыхПодсистем(ВсеОбработчики);
// Подготовка параметров
ВыбиратьРазделенныеОбработчики = Истина;
ВыбиратьНеразделенныеОбработчики = Истина;
Если ОбщегоНазначения.РазделениеВключено() Тогда
Если ПараметрыОтбора.ПолучатьРазделенные Тогда
ВыбиратьНеразделенныеОбработчики = Ложь;
Иначе
Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
ВыбиратьНеразделенныеОбработчики = Ложь;
Иначе
ВыбиратьРазделенныеОбработчики = Ложь;
КонецЕсли;
КонецЕсли;
КонецЕсли;
// Формирование дерева обработчиков.
Схема = ПолучитьОбщийМакет("ПолучениеДереваОбработчиковОбновления");
Схема.Параметры.Найти("ВыбиратьРазделенныеОбработчики").Значение = ВыбиратьРазделенныеОбработчики;
Схема.Параметры.Найти("ВыбиратьНеразделенныеОбработчики").Значение = ВыбиратьНеразделенныеОбработчики;
Схема.Параметры.Найти("ВерсияОт").Значение = ВерсияОт;
Схема.Параметры.Найти("ВерсияДо").Значение = ВерсияДо;
Схема.Параметры.Найти("ВесВерсииОт").Значение = ВесВерсии(Схема.Параметры.Найти("ВерсияОт").Значение);
Схема.Параметры.Найти("ВесВерсииДо").Значение = ВесВерсии(Схема.Параметры.Найти("ВерсияДо").Значение);
Схема.Параметры.Найти("ОперативноеОбновление").Значение = (ПараметрыОтбора.РежимОбновления = "Оперативно");
Схема.Параметры.Найти("ОтложенноеОбновление").Значение = (ПараметрыОтбора.РежимОбновления = "Отложенно");
Если ПараметрыОтбора.УчитыватьПервыйОбменВРИБ Тогда
Схема.Параметры.Найти("ПервыйОбменВРИБ").Значение = ПараметрыОтбора.ПервыйОбменВРИБ;
Схема.Параметры.Найти("ЭтоРИБСФильтром").Значение = СтандартныеПодсистемыПовтИсп.ИспользуетсяРИБ("СФильтром");
КонецЕсли;
Компоновщик = Новый КомпоновщикМакетаКомпоновкиДанных;
Макет = Компоновщик.Выполнить(Схема, Схема.НастройкиПоУмолчанию, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(Макет, Новый Структура("Обработчики", ВсеОбработчики), , Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(Новый ДеревоЗначений);
ВыполняемыеОбработчики = ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КолонкаВерсия = ВыполняемыеОбработчики.Колонки.Версия; // КоллекцияКолонокТаблицыЗначений
КолонкаВерсия.Имя = "ВерсияРегистрации";
КолонкаГруппаВерсии = ВыполняемыеОбработчики.Колонки.ГруппаВерсии; // КоллекцияКолонокТаблицыЗначений
КолонкаГруппаВерсии.Имя = "Версия";
// Сортировка обработчиков по признаку "ОбщиеДанные".
Для Каждого Версия Из ВыполняемыеОбработчики.Строки Цикл
Версия.Строки.Сортировать("ОбщиеДанные Убыв", Истина);
КонецЦикла;
Возврат ВыполняемыеОбработчики;
КонецФункции
// Для внутреннего использования.
//
Функция НеобходимоВыполнитьОбновление(Знач ВерсияМетаданных, Знач ВерсияДанных) Экспорт
Возврат НЕ ПустаяСтрока(ВерсияМетаданных) И ВерсияДанных <> ВерсияМетаданных;
КонецФункции
// Для внутреннего использования.
//
Функция ВыполненаРегистрацияОтложенныхОбработчиковОбновления() Экспорт
УстановитьОтключениеБезопасногоРежима(Истина);
УстановитьПривилегированныйРежим(Истина);
Если ОбщегоНазначения.РазделениеВключено()
И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Возврат Истина; // В неразделенном режиме отложенное обновление не выполняется.
КонецЕсли;
СтандартнаяОбработка = Истина;
Результат = "";
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.ПриПроверкеРегистрацииОтложенныхОбработчиковОбновления(Результат, СтандартнаяОбработка);
КонецЕсли;
Если Не СтандартнаяОбработка Тогда
Возврат Результат;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВерсииПодсистем.ИмяПодсистемы
|ИЗ
| РегистрСведений.ВерсииПодсистем КАК ВерсииПодсистем
|ГДЕ
| ВерсииПодсистем.ВыполненаРегистрацияОтложенныхОбработчиков = ЛОЖЬ";
Результат = Запрос.Выполнить().Выгрузить();
Возврат Результат.Количество() = 0;
КонецФункции
// Возвращает Истина, если у пользователя не отключен показ описания изменений
// системы после обновления и есть непоказанные изменения.
//
Функция ПоказатьОписаниеИзмененийСистемы() Экспорт
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
Если СведенияОбОбновлении.ВыводитьОписаниеОбновлений = Ложь Тогда
Возврат Ложь;
КонецЕсли;
Если Не ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
// Анонимным пользователям новое в версии не показываем.
Возврат Ложь;
КонецЕсли;
Если Не ПравоДоступа("Просмотр", Метаданные.ОбщиеФормы.ОписаниеИзмененийПрограммы) Тогда
Возврат Ложь;
КонецЕсли;
Если ОбщегоНазначения.РазделениеВключено()
И Пользователи.ЭтоПолноправныйПользователь(, Истина) Тогда
Возврат Ложь;
КонецЕсли;
ВывестиОписаниеИзмененийДляАдминистратора = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить("ОбновлениеИБ", "ВывестиОписаниеИзмененийДляАдминистратора",,, ИмяПользователя());
Если ВывестиОписаниеИзмененийДляАдминистратора = Истина Тогда
Возврат Истина;
КонецЕсли;
ПоследняяВерсия = ПоследняяВерсияОтображенияИзмененийСистемы();
Если ПоследняяВерсия = Неопределено Тогда
Возврат Истина;
КонецЕсли;
Разделы = РазделыОписанияИзменений();
Если Разделы = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
Возврат ПолучитьВерсииБольшеЗаданной(Разделы, ПоследняяВерсия).Количество() > 0;
КонецФункции
// Проверяет статус отложенных обработчиков обновления.
//
Функция СтатусНевыполненныхОбработчиков(ПриОбновлении = Ложь) Экспорт
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
Если ПриОбновлении Тогда
ВерсияДанных = ВерсияИБ(Метаданные.Имя);
ВерсияДанныхБезНомераСборки = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(ВерсияДанных);
ВерсияМетаданныхБезНомераСборки = ОбщегоНазначенияКлиентСервер.ВерсияКонфигурацииБезНомераСборки(Метаданные.Версия);
ПодредакцииРавны = (ВерсияДанныхБезНомераСборки = ВерсияМетаданныхБезНомераСборки);
Если ВерсияДанных = "0.0.0.0" Или ПодредакцииРавны Тогда
// В пределах четвертой цифры можно обновляться при наличии невыполненных
// отложенных обработчиков обновления.
Возврат "";
КонецЕсли;
ВерсияДереваОбработчиков = СведенияОбОбновлении.ВерсияДереваОбработчиков;
Если ВерсияДереваОбработчиков <> "" И ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ВерсияДереваОбработчиков, ВерсияДанных) > 0 Тогда
// Если в основном цикле обновления произошла ошибка, то при перезапуске не надо
// проверять дерево отложенных обработчиков, т.к. там будут еще невыполненные
// отложенные обработчики на текущую версию.
Возврат "";
КонецЕсли;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Отложенно);
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.Статус КАК Статус
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.РежимВыполнения = &РежимВыполнения
|
|СГРУППИРОВАТЬ ПО
| ОбработчикиОбновления.Статус";
СтатусыОбработчиков = Запрос.Выполнить().Выгрузить();
Если СтатусыОбработчиков.Найти(Перечисления.СтатусыОбработчиковОбновления.НеВыполнялся) <> Неопределено Тогда
Возврат "СтатусНеВыполнено";
ИначеЕсли СтатусыОбработчиков.Найти(Перечисления.СтатусыОбработчиковОбновления.Ошибка) <> Неопределено Тогда
Возврат "СтатусОшибка";
ИначеЕсли СтатусыОбработчиков.Найти(Перечисления.СтатусыОбработчиковОбновления.Приостановлен) <> Неопределено Тогда
Возврат "СтатусПриостановлен";
Иначе
Возврат "";
КонецЕсли;
КонецФункции
// Выполняет все процедуры отложенного обновления в цикле за один вызов.
//
Процедура ВыполнитьОтложенноеОбновлениеСейчас(ПараметрыОбновления = Неопределено) Экспорт
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
Если СведенияОбОбновлении.ВремяОкончаниеОтложенногоОбновления <> Неопределено Тогда
Возврат;
КонецЕсли;
Если СведенияОбОбновлении.ВремяНачалаОтложенногоОбновления = Неопределено Тогда
СведенияОбОбновлении.ВремяНачалаОтложенногоОбновления = ТекущаяДатаСеанса();
КонецЕсли;
Если ТипЗнч(СведенияОбОбновлении.НомерСеанса) <> Тип("СписокЗначений") Тогда
СведенияОбОбновлении.НомерСеанса = Новый СписокЗначений;
КонецЕсли;
СведенияОбОбновлении.НомерСеанса.Добавить(НомерСеансаИнформационнойБазы());
ЗаписатьСведенияОбОбновленииИнформационнойБазы(СведенияОбОбновлении);
ОбработчикиВыполнялись = Истина;
Пока ОбработчикиВыполнялись Цикл
ОбработчикиВыполнялись = ВыполнитьОтложенныйОбработчикОбновления(ПараметрыОбновления);
Если ОбработчикиВыполнялись Тогда
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
Если СведенияОбОбновлении.ОтложенноеОбновлениеЗавершеноУспешно <> Неопределено Тогда
Прервать;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// Для внутреннего использования.
Функция ДобавитьПараметрыРаботыКлиентаПриЗапуске(Параметры) Экспорт
Параметры.Вставить("ВерсияДанныхОсновнойКонфигурации", ВерсияИБ(Метаданные.Имя));
Если НеобходимоОбновлениеНеразделенныхДанныхИнформационнойБазы() Тогда
Параметры.Вставить("НеобходимоОбновлениеНеразделенныхДанных");
КонецЕсли;
// Проверка продолжения работы.
ЭтоВызовПередНачаломРаботыСистемы = Параметры.ПолученныеПараметрыКлиента <> Неопределено;
ОписаниеОшибки = ИнформационнаяБазаЗаблокированаДляОбновления(, ЭтоВызовПередНачаломРаботыСистемы);
Если ЗначениеЗаполнено(ОписаниеОшибки) Тогда
Параметры.Вставить("ИнформационнаяБазаЗаблокированаДляОбновления", ОписаниеОшибки);
// Работа будет завершена.
Возврат Ложь;
КонецЕсли;
Если ТребуетсяПроверитьЛегальностьПолученияОбновления() Тогда
Параметры.Вставить("ПроверитьЛегальностьПолученияОбновления");
КонецЕсли;
Возврат Истина;
КонецФункции
// АПК:581-выкл Используется при тестировании.
Функция ТребуетсяПроверитьЛегальностьПолученияОбновления() Экспорт
Если НЕ ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПроверкаЛегальностиПолученияОбновления") Тогда
Возврат Ложь;
КонецЕсли;
Если СтандартныеПодсистемыСервер.ЭтоБазоваяВерсияКонфигурации() Тогда
Возврат Ложь;
КонецЕсли;
Если ОбщегоНазначения.РазделениеВключено() Тогда
Возврат Ложь;
КонецЕсли;
Если ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ() Тогда
Возврат Ложь;
КонецЕсли;
ЛегальнаяВерсия = "";
Если РежимОбновленияДанныхВЛокальномРежимеРаботы() = "НачальноеЗаполнение" Тогда
ЛегальнаяВерсия = Метаданные.Версия;
Иначе
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
ЛегальнаяВерсия = СведенияОбОбновлении.ЛегальнаяВерсия;
КонецЕсли;
Возврат ЛегальнаяВерсия <> Метаданные.Версия;
КонецФункции
// АПК:581-вкл
// Возвращает текст причины блокировки, если требуется обновление ИБ и у текущего пользователя
// для этого недостаточно прав, иначе возвращает пустую строку.
//
// Параметры:
// УчитыватьПривилегированныйРежим - Булево - если указать Ложь, то при проверке прав текущего пользователя
// наличие привилегированного режима не будет учитываться.
//
// Возвращаемое значение:
// Строка - если база не заблокирована, тогда пустая строка, иначе сообщение о причине блокировки.
//
Функция ИнформационнаяБазаЗаблокированаДляОбновления(УчитыватьПривилегированныйРежим = Истина, ПриЗапуске = Неопределено) Экспорт
Сообщение = "";
ТекущийПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь();
// Для входа в заблокированную базу достаточно только одного права администрирования.
Если УчитыватьПривилегированныйРежим Тогда
ЕстьПравоАдминистрирование = ПравоДоступа("Администрирование", Метаданные);
Иначе
ЕстьПравоАдминистрирование = ПравоДоступа("Администрирование", Метаданные, ТекущийПользовательИБ);
КонецЕсли;
СообщениеАдминистраторуСистемы =
НСтр("ru = 'Вход в программу временно невозможен в связи с обновлением на новую версию.
|Для завершения обновления версии программы требуются административные права
|(роли ""Администратор системы"" и ""Полные права"").'");
УстановитьПривилегированныйРежим(Истина);
РазделениеВключено = ОбщегоНазначения.РазделениеВключено();
ДоступноИспользованиеРазделенныхДанных = ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных();
УстановитьПривилегированныйРежим(Ложь);
Если НеобходимоОбновлениеНеразделенныхДанныхИнформационнойБазы() Тогда
СообщениеАдминистраторуОбластиДанных =
НСтр("ru = 'Вход в приложение временно невозможен в связи с обновлением на новую версию.
|Обратитесь к администратору сервиса за подробностями.'");
Если ДоступноИспользованиеРазделенныхДанных Тогда
Сообщение = СообщениеАдминистраторуОбластиДанных;
ИначеЕсли НЕ ЕстьПраваНаОбновлениеИнформационнойБазы(УчитыватьПривилегированныйРежим, Ложь) Тогда
Если ЕстьПравоАдминистрирование Тогда
Сообщение = СообщениеАдминистраторуСистемы;
Иначе
Сообщение = СообщениеАдминистраторуОбластиДанных;
КонецЕсли;
КонецЕсли;
Возврат Сообщение;
КонецЕсли;
// Сообщение администратору сервиса не выдается.
Если РазделениеВключено И Не ДоступноИспользованиеРазделенныхДанных Тогда
Возврат "";
КонецЕсли;
Если ЕстьПраваНаОбновлениеИнформационнойБазы(УчитыватьПривилегированныйРежим, Истина) Тогда
Если ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы()
И ПриЗапуске = Истина Тогда
Результат = ОтметкаНачалаОбновления();
Если Не Результат.МожноВыполнятьОбновление Тогда
Сообщение = НСтр("ru = 'Вход в программу временно невозможен в связи с обновлением на новую версию.
|Обновление уже выполняется:
| компьютер - %1
| пользователь - %2
| сеанс - %3
| начат - %4
| приложение - %5'");
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Сообщение,
Результат.СеансОбновления.ИмяКомпьютера,
Результат.СеансОбновления.Пользователь,
Результат.СеансОбновления.НомерСеанса,
Результат.СеансОбновления.НачалоСеанса,
Результат.СеансОбновления.ИмяПриложения);
Возврат Сообщение;
КонецЕсли;
КонецЕсли;
Возврат "";
КонецЕсли;
ТребуетсяПовторитьЗагрузкуСообщенияОбменаДаннымиПередЗапуском = Ложь;
Если ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ()
И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда
МодульОбменДаннымиСлужебный = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСлужебный");
ТребуетсяПовторитьЗагрузкуСообщенияОбменаДаннымиПередЗапуском =
МодульОбменДаннымиСлужебный.ПовторитьЗагрузкуСообщенияОбменаДаннымиПередЗапуском();
КонецЕсли;
// В этих случаях запуск не блокируется.
Если Не ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы()
И Не ТребуетсяПроверитьЛегальностьПолученияОбновления()
И Не ТребуетсяПовторитьЗагрузкуСообщенияОбменаДаннымиПередЗапуском Тогда
Возврат "";
КонецЕсли;
// Во всех остальных случаях запуск блокируется.
Если ЕстьПравоАдминистрирование Тогда
Возврат СообщениеАдминистраторуСистемы;
КонецЕсли;
Если РазделениеВключено Тогда
// Сообщение пользователю сервиса.
Сообщение =
НСтр("ru = 'Вход в приложение временно невозможен в связи с обновлением на новую версию.
|Обратитесь к администратору сервиса за подробностями.'");
Иначе
// Сообщение пользователю локального режима.
Сообщение =
НСтр("ru = 'Вход в программу временно невозможен в связи с обновлением на новую версию.
|Обратитесь к администратору за подробностями.'");
КонецЕсли;
Возврат Сообщение;
КонецФункции
// Устанавливает состояние запуска обновления информационной.
// Требуется привилегированный режим.
//
// Параметры:
// Запуск - Булево - если установить Истина, состояние будет установлено,
// если установить Ложь, состояние будет снято.
//
Процедура УстановитьЗапускОбновленияИнформационнойБазы(Запуск) Экспорт
УстановитьПривилегированныйРежим(Истина);
ТекущиеПараметры = Новый Соответствие(ПараметрыСеанса.ПараметрыКлиентаНаСервере);
Если Запуск = Истина Тогда
ТекущиеПараметры.Вставить("ЗапуститьОбновлениеИнформационнойБазы", Истина);
ИначеЕсли ТекущиеПараметры.Получить("ЗапуститьОбновлениеИнформационнойБазы") <> Неопределено Тогда
ТекущиеПараметры.Удалить("ЗапуститьОбновлениеИнформационнойБазы");
КонецЕсли;
ПараметрыСеанса.ПараметрыКлиентаНаСервере = Новый ФиксированноеСоответствие(ТекущиеПараметры);
КонецПроцедуры
// Получает сведения об обновлении информационной базы
// из константы "СведенияОбОбновленииИБ".
//
// Возвращаемое значение:
// Структура:
// * ВремяНачалаОбновления - Строка
// * ВремяОкончанияОбновления - Строка
// * ПродолжительностьОбновления - Строка
// * ВремяНачалаОтложенногоОбновления - Строка
// * ВремяОкончаниеОтложенногоОбновления - Строка
// * НомерСеанса - СписокЗначений
// * ПараметрыОбработчикаОбновления - Структура
// * ОтложенноеОбновлениеЗавершеноУспешно - Строка
// * ДеревоОбработчиков - ДеревоЗначений
// * ВерсияДереваОбработчиков - Строка
// * ВыводитьОписаниеОбновлений - Булево
// * ЛегальнаяВерсия - Строка
// * НовыеПодсистемы - Массив
// * УправлениеОтложеннымОбновлением - Структура
// * ОбрабатываемыеДанные - Соответствие
// * ТекущаяИтерацияОбновления - Число
// * ПланОтложенногоОбновления - Массив
// * СеансОбновления - Структура
// * ОписаниеПотоков - см. НовоеОписаниеПотоковРегистрацииДанныхОтложенногоОбновления
// * ВерсияУдалениеПатчей - Строка
//
Функция СведенияОбОбновленииИнформационнойБазы() Экспорт
УстановитьПривилегированныйРежим(Истина);
Если ОбщегоНазначения.РазделениеВключено()
И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Возврат НовыеСведенияОбОбновлении();
КонецЕсли;
СведенияОбОбновленииИБ = Константы.СведенияОбОбновленииИБ.Получить().Получить();
Если ТипЗнч(СведенияОбОбновленииИБ) <> Тип("Структура") Тогда
Возврат НовыеСведенияОбОбновлении();
КонецЕсли;
Если СведенияОбОбновленииИБ.Количество() = 1 Тогда
Возврат НовыеСведенияОбОбновлении();
КонецЕсли;
СведенияОбОбновленииИБ = НовыеСведенияОбОбновлении(СведенияОбОбновленииИБ);
Возврат СведенияОбОбновленииИБ;
КонецФункции
// Записывает данные по обновлению в константу "СведенияОбОбновленииИБ".
//
Процедура ЗаписатьСведенияОбОбновленииИнформационнойБазы(Знач СведенияОбОбновлении) Экспорт
Если СведенияОбОбновлении = Неопределено Тогда
НовоеЗначение = НовыеСведенияОбОбновлении();
Иначе
НовоеЗначение = СведенияОбОбновлении;
КонецЕсли;
МенеджерКонстанты = Константы.СведенияОбОбновленииИБ.СоздатьМенеджерЗначения();
МенеджерКонстанты.Значение = Новый ХранилищеЗначения(НовоеЗначение);
ОбновлениеИнформационнойБазы.ЗаписатьДанные(МенеджерКонстанты);
КонецПроцедуры
// Записывает в константу продолжительность основного цикла обновления.
//
Процедура ЗаписатьВремяВыполненияОбновления(ВремяНачалаОбновления, ВремяОкончанияОбновления) Экспорт
Если ОбщегоНазначения.РазделениеВключено() И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Возврат;
КонецЕсли;
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
СведенияОбОбновлении.ВремяНачалаОбновления = ВремяНачалаОбновления;
СведенияОбОбновлении.ВремяОкончанияОбновления = ВремяОкончанияОбновления;
ВремяВСекундах = ВремяОкончанияОбновления - ВремяНачалаОбновления;
Часы = Цел(ВремяВСекундах/3600);
Минуты = Цел((ВремяВСекундах - Часы * 3600) / 60);
Секунды = ВремяВСекундах - Часы * 3600 - Минуты * 60;
ПродолжительностьЧасы = ?(Часы = 0, "", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 час'"), Часы));
ПродолжительностьМинуты = ?(Минуты = 0, "", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 мин'"), Минуты));
ПродолжительностьСекунды = ?(Секунды = 0, "", СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 сек'"), Секунды));
ПродолжительностьОбновления = ПродолжительностьЧасы + " " + ПродолжительностьМинуты + " " + ПродолжительностьСекунды;
СведенияОбОбновлении.ПродолжительностьОбновления = СокрЛП(ПродолжительностьОбновления);
ЗаписатьСведенияОбОбновленииИнформационнойБазы(СведенияОбОбновлении);
КонецПроцедуры
// Только для внутреннего использования.
Процедура ЗаписатьПодтверждениеЛегальностиПолученияОбновлений() Экспорт
Если ОбщегоНазначения.РазделениеВключено()
И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных()
Или СтандартныеПодсистемыСервер.ЭтоБазоваяВерсияКонфигурации() Тогда
Возврат;
КонецЕсли;
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
СведенияОбОбновлении.ЛегальнаяВерсия = Метаданные.Версия;
ЗаписатьСведенияОбОбновленииИнформационнойБазы(СведенияОбОбновлении);
КонецПроцедуры
// Устанавливает флаг отображения описаний изменений версий по
// текущую версию включительно, если для пользователя флаг не
// был установлен ранее.
//
// Параметры:
// ИмяПользователя - Строка - имя пользователя, для которого
// необходимо установить флаг.
//
Процедура УстановитьФлагОтображенияОписанийДляНовогоПользователя(Знач ИмяПользователя) Экспорт
Если ПоследняяВерсияОтображенияИзмененийСистемы(ИмяПользователя) = Неопределено Тогда
УстановитьФлагОтображенияОписанийПоТекущуюВерсию(ИмяПользователя);
КонецЕсли;
КонецПроцедуры
// Повторно регистрирует обновляемые данные на плане обмена
// ОбновлениеИнформационнойБазы, требуется при загрузке данных
// из сервиса в коробку и обратно.
//
Процедура ПеререгистрироватьДанныеДляОтложенногоОбновления() Экспорт
ПараметрыИнициализированы = Ложь;
Обработчики = ОбработчикиДляОтложеннойРегистрацииДанных();
Для Каждого Обработчик Из Обработчики Цикл
Если Не ПараметрыИнициализированы Тогда
ПараметрыОбработчикаСтруктура = ОбновлениеИнформационнойБазы.ОсновныеПараметрыОтметкиКОбработке();
ПараметрыОбработчикаСтруктура.ПовторнаяРегистрация = Истина;
ПараметрыИнициализированы = Истина;
КонецЕсли;
ПараметрыОбработчикаСтруктура.Очередь = Обработчик.ОчередьОтложеннойОбработки;
ПараметрыОбработчикаСтруктура.ИмяОбработчика = Обработчик.ИмяОбработчика;
ПараметрыОбработчикаСтруктура.Вставить("ДанныеОбработчика", Новый Соответствие);
Если Обработчик.Многопоточный Тогда
ПараметрыОбработчикаСтруктура.ПараметрыВыборки =
ОбновлениеИнформационнойБазы.ДополнительныеПараметрыВыборкиДанныхДляМногопоточнойОбработки();
Иначе
ПараметрыОбработчикаСтруктура.ПараметрыВыборки = Неопределено;
КонецЕсли;
ПараметрыОбработчика = Новый Массив;
ПараметрыОбработчика.Добавить(ПараметрыОбработчикаСтруктура);
Попытка
Сообщение = НСтр("ru = 'Выполняется процедура заполнения данных
|""%1""
|отложенного обработчика обновления
|""%2"".'");
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Сообщение,
Обработчик.ПроцедураЗаполненияДанныхОбновления,
Обработчик.ИмяОбработчика);
ЗаписатьИнформацию(Сообщение);
ОбщегоНазначения.ВыполнитьМетодКонфигурации(Обработчик.ПроцедураЗаполненияДанныхОбновления, ПараметрыОбработчика);
Если Обработчик.Многопоточный Тогда
ИсправитьПолныеИменаВПараметрахВыборки(ПараметрыОбработчикаСтруктура.ПараметрыВыборки);
КонецЕсли;
Исключение
ЗаписатьОшибку(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'При вызове процедуры заполнения данных
|""%1""
|отложенного обработчика обновления
|""%2""
|произошла ошибка:
|""%3"".'"),
Обработчик.ПроцедураЗаполненияДанныхОбновления,
Обработчик.ИмяОбработчика,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
ВызватьИсключение;
КонецПопытки;
ОписаниеОбрабатываемыхДанных = НовоеОписаниеОбрабатываемыхДанных(Обработчик.Многопоточный);
ОписаниеОбрабатываемыхДанных.ДанныеОбработчика = ПараметрыОбработчикаСтруктура.ДанныеОбработчика;
ОписаниеОбрабатываемыхДанных.ИмяОбработчика = Обработчик.ИмяОбработчика;
Если Обработчик.Многопоточный Тогда
ОписаниеОбрабатываемыхДанных.ПараметрыВыборки = ПараметрыОбработчикаСтруктура.ПараметрыВыборки;
КонецЕсли;
ОписаниеОбрабатываемыхДанных = Новый ХранилищеЗначения(ОписаниеОбрабатываемыхДанных, Новый СжатиеДанных(9));
УстановитьСвойствоОбработчика(Обработчик.ИмяОбработчика, "ОбрабатываемыеДанные", ОписаниеОбрабатываемыхДанных);
КонецЦикла;
КонецПроцедуры
// Возвращает параметры отложенного обработчика обновления.
// Проверяет, есть ли сохраненные параметры у обработчика обновления
// и возвращает их.
//
// Параметры:
// Идентификатор - Строка
// - УникальныйИдентификатор - имя процедуры обработчика или
// его уникальный идентификатор.
//
// Возвращаемое значение:
// Структура - сохраненные параметры обработчика обновления.
//
Функция ПараметрыОтложенногоОбработчикаОбновления(Идентификатор) Экспорт
ОбработчикОбновления = ОбработчикОбновления(Идентификатор);
Если ОбработчикОбновления = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
СтатистикаВыполнения = ОбработчикОбновления.СтатистикаВыполнения.Получить();
Параметры = СтатистикаВыполнения["ПараметрыОбработчика"];
Если Параметры = Неопределено Тогда
Параметры = Новый Структура;
КонецЕсли;
Возврат Параметры;
КонецФункции
// Записывает параметры отложенного обработчика обновления
//
// Параметры:
// Идентификатор - Строка
// - УникальныйИдентификатор - имя процедуры обработчика или
// его уникальный идентификатор.
// Параметры - Структура - параметры, которые необходимо сохранить.
//
Процедура ЗаписатьПараметрыОтложенногоОбработчикаОбновления(Идентификатор, Параметры) Экспорт
ОбработчикОбновления = ОбработчикОбновления(Идентификатор);
Если ОбработчикОбновления = Неопределено Тогда
Возврат;
КонецЕсли;
СтатистикаВыполнения = ОбработчикОбновления.СтатистикаВыполнения.Получить();
СтатистикаВыполнения.Вставить("ПараметрыОбработчика", Параметры);
УстановитьСвойствоОбработчика(Идентификатор,
"СтатистикаВыполнения",
Новый ХранилищеЗначения(СтатистикаВыполнения));
КонецПроцедуры
// Возвращает количество потоков обновления информационной базы.
//
// Если количество указано в параметре запуска "ЧислоПотоковОбновления", то возвращается оно.
// Иначе, если значение константы КоличествоПотоковОбновленияИнформационнойБазы установлено, то возвращается оно.
// Иначе возвращается значение по умолчанию, см. КоличествоПотоковОбновленияИнформационнойБазыПоУмолчанию.
//
// Возвращаемое значение:
// Число - количество потоков.
//
Функция КоличествоПотоковОбновленияИнформационнойБазы() Экспорт
Если РазрешеноМногопоточноеОбновление() Тогда
Количество = 0;
ИмяПараметра = "ЧислоПотоковОбновления=";
Параметры = ПараметрыСеанса.ПараметрыКлиентаНаСервере.Получить("ПараметрЗапуска");
ПозицияПараметра = СтрНайти(Параметры, ИмяПараметра);
Если ПозицияПараметра > 0 Тогда
ПозицияРазделителя = СтрНайти(Параметры, ";",, ПозицияПараметра + СтрДлина(ИмяПараметра));
Длина = ?(ПозицияРазделителя > 0, ПозицияРазделителя, СтрДлина(Параметры) + 1) - ПозицияПараметра;
ПотокиОбновления = СтрРазделить(Сред(Параметры, ПозицияПараметра, Длина), "=");
Попытка
Количество = Число(ПотокиОбновления[1]);
Исключение
ТекстИсключения = НСтр(
"ru = 'Укажите параметр запуска программы ""%1"" в формате
|""%1=Х"", где ""Х"" - максимальное количество потоков обновления.'");
ТекстИсключения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстИсключения, "ЧислоПотоковОбновления");
ВызватьИсключение ТекстИсключения;
КонецПопытки;
КонецЕсли;
Если Количество = 0 Тогда
Количество = Константы.КоличествоПотоковОбновленияИнформационнойБазы.Получить();
Если Количество = 0 Тогда
Количество = КоличествоПотоковОбновленияИнформационнойБазыПоУмолчанию();
КонецЕсли;
КонецЕсли;
Возврат Количество;
Иначе
Возврат 1;
КонецЕсли;
КонецФункции
// Возвращает итерации обновления.
//
// Возвращаемое значение:
// Массив из см. ИтерацияОбновления
//
Функция ИтерацииОбновления() Экспорт
ИмяОсновнойКонфигурации = Метаданные.Имя;
ИтерацияОбновлениеОсновнойПодсистемы = Неопределено;
ИтерацииОбновления = Новый Массив;
ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем();
Для каждого ИмяПодсистемы Из ОписанияПодсистем.Порядок Цикл
ОписаниеПодсистемы = ОписанияПодсистем.ПоИменам.Получить(ИмяПодсистемы);
Если НЕ ЗначениеЗаполнено(ОписаниеПодсистемы.ОсновнойСерверныйМодуль) Тогда
Продолжить;
КонецЕсли;
Модуль = ОбщегоНазначения.ОбщийМодуль(ОписаниеПодсистемы.ОсновнойСерверныйМодуль);
ИтерацияОбновления = ИтерацияОбновления(ОписаниеПодсистемы.Имя, ОписаниеПодсистемы.Версия,
ОбновлениеИнформационнойБазы.НоваяТаблицаОбработчиковОбновления(), ОписаниеПодсистемы.Имя = ИмяОсновнойКонфигурации);
ИтерацияОбновления.ИмяОсновногоСерверногоМодуля = ОписаниеПодсистемы.ОсновнойСерверныйМодуль;
ИтерацияОбновления.ОсновнойСерверныйМодуль = Модуль;
ИтерацияОбновления.ПредыдущаяВерсия = ВерсияИБ(ОписаниеПодсистемы.Имя);
ИтерацииОбновления.Добавить(ИтерацияОбновления);
Модуль.ПриДобавленииОбработчиковОбновления(ИтерацияОбновления.Обработчики);
Если ОписаниеПодсистемы.Имя = ИмяОсновнойКонфигурации Тогда
ИтерацияОбновлениеОсновнойПодсистемы = ИтерацияОбновления;
КонецЕсли;
ПроверитьСвойстваОбработчиков(ИтерацияОбновления);
КонецЦикла;
Если ИтерацияОбновлениеОсновнойПодсистемы = Неопределено И ИмяОсновнойКонфигурации = "БиблиотекаСтандартныхПодсистем" Тогда
ТекстСообщения = НСтр("ru = 'Файл поставки 1С:Библиотека стандартных подсистем не предназначен для создания
|информационных баз по шаблону. Перед использованием необходимо
|ознакомиться с документацией на ИТС (http://its.1c.ru/db/bspdoc)'");
ВызватьИсключение ТекстСообщения;
КонецЕсли;
Возврат ИтерацииОбновления;
КонецФункции
// АПК:581-выкл Для механизма обновления ИБ в копии.
// Обновляет список выполняемых обработчиков обновления в регистрах сведений
// ОбработчикиОбновления и ОбработчикиОбновленияОбщихДанных.
//
Процедура ОбновитьСписокВыполняемыхОбработчиковОбновления(ИтерацииОбновления, ПервыйОбменВРИБ = Ложь, ТипыОбработчиков = Неопределено) Экспорт
ТолькоОтложенные = (ТипыОбработчиков = "Отложенные");
ТолькоМонопольные = (ТипыОбработчиков = "Монопольные");
Если Не ТолькоМонопольные Тогда
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
НезавершенныеОтложенныеОбработчики = НезавершенныеОтложенныеОбработчики(СведенияОбОбновлении);
КонецЕсли;
НачатьТранзакцию();
Попытка
Если Не ТолькоМонопольные Тогда
ВерсииПодсистемНаНачалоОбновления = Новый Соответствие;
ОтложенноеОбновлениеЗавершеноУспешно = Неопределено;
ЗаполнитьВерсииПодсистем = Ложь;
Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
ОтложенноеОбновлениеЗавершеноУспешно = Константы.ОтложенноеОбновлениеЗавершеноУспешно.Получить();
ВерсииПодсистемНаНачалоОбновления = СведенияОбОбновлении.ВерсииПодсистемНаНачалоОбновления;
ЗаполнитьВерсииПодсистем = Истина;
КонецЕсли;
Если ОтложенноеОбновлениеЗавершеноУспешно = Истина Тогда
ВерсииПодсистемНаНачалоОбновления.Очистить();
КонецЕсли;
СброситьСведенияОбОбновлении(СведенияОбОбновлении);
ПроверитьУникальностьИдентификаторовОтложенныхОбработчиков(ИтерацииОбновления);
КонецЕсли;
// АПК:1327-выкл нет конкурентной работы с регистром
Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
НаборРазделенныхОбработчиков = РегистрыСведений.ОбработчикиОбновления.СоздатьНаборЗаписей();
Если ТолькоМонопольные Тогда
// Остаются только отложенные обработчики, монопольные и оперативные добавляются заново.
НаборРазделенныхОбработчиков.Прочитать();
ТаблицаОбработчиков = НаборРазделенныхОбработчиков.Выгрузить();
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Отложенно);
ТаблицаОбработчиков = ТаблицаОбработчиков.Скопировать(ПараметрыОтбора);
НаборРазделенныхОбработчиков.Загрузить(ТаблицаОбработчиков);
ИначеЕсли ТолькоОтложенные Тогда
// Монопольные и оперативные обработчики остаются, т.к. повторно регистрируются только отложенные.
НаборРазделенныхОбработчиков.Прочитать();
ТаблицаОбработчиков = НаборРазделенныхОбработчиков.Выгрузить();
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Монопольно);
МонопольныеОбработчики = ТаблицаОбработчиков.Скопировать(ПараметрыОтбора);
ПараметрыОтбора.Вставить("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Оперативно);
ОперативныеОбработчики = ТаблицаОбработчиков.Скопировать(ПараметрыОтбора);
ОбщегоНазначенияКлиентСервер.ДополнитьТаблицу(МонопольныеОбработчики, ОперативныеОбработчики);
НаборРазделенныхОбработчиков.Загрузить(ОперативныеОбработчики);
КонецЕсли;
НаборРазделенныхОбработчиков.Записать();
КонецЕсли;
Если Не ТолькоОтложенные И Не ОбщегоНазначения.РазделениеВключено() Или Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
НаборНеразделенныхОбработчиков = РегистрыСведений.ОбработчикиОбновленияОбщихДанных.СоздатьНаборЗаписей();
НаборНеразделенныхОбработчиков.Записать();
КонецЕсли;
// АПК:1327-вкл
ОписанияБиблиотек = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем().ПоИменам;
ГруппаОбновления = 1;
ТекущийРежимВыполнения = "";
ТекстОшибок = "";
ДобавленныеОбработчики = Новый Массив;
Для Каждого ИтерацияОбновления Из ИтерацииОбновления Цикл
Если Не ТолькоМонопольные И ЗаполнитьВерсииПодсистем Тогда
СохраненнаяВерсия = ВерсииПодсистемНаНачалоОбновления[ИтерацияОбновления.Подсистема];
Если СохраненнаяВерсия = Неопределено Тогда
ВерсииПодсистемНаНачалоОбновления.Вставить(ИтерацияОбновления.Подсистема, ИтерацияОбновления.ПредыдущаяВерсия);
Иначе
Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(СохраненнаяВерсия, ИтерацияОбновления.ПредыдущаяВерсия) > 0 Тогда
ВерсииПодсистемНаНачалоОбновления.Вставить(ИтерацияОбновления.Подсистема, ИтерацияОбновления.ПредыдущаяВерсия);
КонецЕсли;
КонецЕсли;
КонецЕсли;
// Добавление монопольных и оперативных обработчиков обновления.
ИмяБиблиотеки = ИтерацияОбновления.Подсистема;
Если Не ТолькоОтложенные Тогда
Если Не ПервыйОбменВРИБ Тогда
ПредыдущаяВерсия = ИтерацияОбновления.ПредыдущаяВерсия;
ВерсияМетаданных = ИтерацияОбновления.Версия;
Если ПустаяСтрока(ВерсияМетаданных) Тогда
ВерсияМетаданных = "0.0.0.0";
КонецЕсли;
ОбработчикиПоВерсиям = Неопределено;
Если ПредыдущаяВерсия <> "0.0.0.0"
И ОбщегоНазначения.РазделениеВключено()
И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
ОбработчикиПоВерсиям = ПолучитьПланОбновления(ИтерацияОбновления.Подсистема, ПредыдущаяВерсия, ВерсияМетаданных);
КонецЕсли;
Если ОбработчикиПоВерсиям = Неопределено Тогда
ОбработчикиПоВерсиям = ОбработчикиОбновленияВИнтервале(ИтерацияОбновления.Обработчики,
ПредыдущаяВерсия, ИтерацияОбновления.Версия);
КонецЕсли;
Если ОбработчикиПоВерсиям.Строки.Количество() <> 0 Тогда
ОбработчикиПоВерсиям.Колонки.Процедура.Имя = "ИмяОбработчика";
ДобавитьОбработчики(ИмяБиблиотеки, ОбработчикиПоВерсиям.Строки, ДобавленныеОбработчики);
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если ТолькоМонопольные Тогда
Продолжить;
КонецЕсли;
// Добавление отложенных обработчиков обновления.
Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
// Обработка сценария получения первого сообщения обмена от подчиненного узла после обновления.
ПредыдущаяВерсия = ?(ПервыйОбменВРИБ, "1.0.0.0", ИтерацияОбновления.ПредыдущаяВерсия);
РежимВыполненияОтложенныхОбработчиков = ОписанияБиблиотек[ИмяБиблиотеки].РежимВыполненияОтложенныхОбработчиков;
ПараллельноСВерсии = ОписанияБиблиотек[ИмяБиблиотеки].ПараллельноеОтложенноеОбновлениеСВерсии;
Если ПервыйОбменВРИБ И РежимВыполненияОтложенныхОбработчиков = "Последовательно" Тогда
Продолжить;
КонецЕсли;
ПараметрыОтбора = ПараметрыОтбораОбработчиков();
ПараметрыОтбора.ПолучатьРазделенные = Истина;
ПараметрыОтбора.РежимОбновления = "Отложенно";
ПараметрыОтбора.УчитыватьПервыйОбменВРИБ = (РежимВыполненияОтложенныхОбработчиков = "Параллельно");
ПараметрыОтбора.ПервыйОбменВРИБ = ПервыйОбменВРИБ;
ОбработчикиПоВерсиям = ОбработчикиОбновленияВИнтервале(ИтерацияОбновления.Обработчики,
ПредыдущаяВерсия, ИтерацияОбновления.Версия, ПараметрыОтбора);
ОбработчикиПоВерсиям.Колонки.Процедура.Имя = "ИмяОбработчика";
ДобавитьНезавершенныеОтложенныеОбработчики(
ИтерацияОбновления,
ИмяБиблиотеки,
НезавершенныеОтложенныеОбработчики,
ОбработчикиПоВерсиям.Строки);
Если ПервыйОбменВРИБ Тогда
УдаляемыеСтроки = Новый Массив;
Для Каждого СтрокаВерсия Из ОбработчикиПоВерсиям.Строки Цикл
Если СтрокаВерсия.Версия = "*"
Или (ЗначениеЗаполнено(ПараллельноСВерсии)
И ОбщегоНазначенияКлиентСервер.СравнитьВерсии(СтрокаВерсия.Версия, ПараллельноСВерсии) < 0) Тогда
УдаляемыеСтроки.Добавить(СтрокаВерсия);
КонецЕсли;
КонецЦикла;
Для Каждого УдаляемаяСтрока Из УдаляемыеСтроки Цикл
ОбработчикиПоВерсиям.Строки.Удалить(УдаляемаяСтрока);
КонецЦикла;
КонецЕсли;
Если ОбработчикиПоВерсиям.Строки.Количество() = 0 Тогда
Продолжить;
КонецЕсли;
УпорядочитьВерсииОбработчиков(ОбработчикиПоВерсиям);
ДобавитьОтложенныеОбработчики(ИмяБиблиотеки, ОбработчикиПоВерсиям.Строки, ГруппаОбновления, ТекстОшибок, ТекущийРежимВыполнения);
КонецЕсли;
КонецЦикла;
Если ЗначениеЗаполнено(ТекстОшибок) Тогда
ВызватьИсключение ТекстОшибок;
КонецЕсли;
Если Не ТолькоМонопольные И ЗаполнитьВерсииПодсистем Тогда
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
СведенияОбОбновлении.ВерсииПодсистемНаНачалоОбновления = ВерсииПодсистемНаНачалоОбновления;
ЗаписатьСведенияОбОбновленииИнформационнойБазы(СведенияОбОбновлении);
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
// АПК:581-вкл
// Вызывается для включения и отключении отложенного обновления.
//
// Параметры:
// Использование - Булево - Истина, если задание нужно включить, иначе Ложь.
//
Процедура ПриВключенииОтложенногоОбновления(Использование) Экспорт
ОтборЗаданий = Новый Структура;
ОтборЗаданий.Вставить("Метаданные", Метаданные.РегламентныеЗадания.ОтложенноеОбновлениеИБ);
Задания = РегламентныеЗаданияСервер.НайтиЗадания(ОтборЗаданий);
Для Каждого Задание Из Задания Цикл
Если Задание.Использование = Использование Тогда
Продолжить;
КонецЕсли;
ПараметрыЗадания = Новый Структура("Использование", Использование);
ТребуетсяУстановитьЗапланированныйМоментЗапуска = Ложь;
Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
МодульТехнологияСервиса = ОбщегоНазначения.ОбщийМодуль("ТехнологияСервиса");
ВерсияБиблиотекиБТС = МодульТехнологияСервиса.ВерсияБиблиотеки();
ТребуетсяУстановитьЗапланированныйМоментЗапуска = ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ВерсияБиблиотекиБТС, "2.0.1.0") > 0;
КонецЕсли;
Если ОбщегоНазначения.РазделениеВключено()
И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса")
И Использование
И ТребуетсяУстановитьЗапланированныйМоментЗапуска Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
ЗапланированныйМоментЗапуска = МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.ЗапланированныйМоментЗапускаОбновленияОбласти();
ПараметрыЗадания.Вставить("ЗапланированныйМоментЗапуска", ЗапланированныйМоментЗапуска);
КонецЕсли;
РегламентныеЗаданияСервер.ИзменитьЗадание(Задание.УникальныйИдентификатор, ПараметрыЗадания);
КонецЦикла;
КонецПроцедуры
// Выполняет оперативные и монопольные обработчики обновления
// по переданной итерации обновления.
//
Функция ВыполнитьИтерациюОбновления(Знач ИтерацияОбновления, Знач Параметры) Экспорт
ИдентификаторБиблиотеки = ИтерацияОбновления.Подсистема;
ВерсияМетаданныхИБ = ИтерацияОбновления.Версия;
ОбработчикиОбновления = ИтерацияОбновления.Обработчики;
ТекущаяВерсияИБ = ИтерацияОбновления.ПредыдущаяВерсия;
НоваяВерсияИБ = ТекущаяВерсияИБ;
ВерсияМетаданных = ВерсияМетаданныхИБ;
Если ПустаяСтрока(ВерсияМетаданных) Тогда
ВерсияМетаданных = "0.0.0.0";
КонецЕсли;
Если ТекущаяВерсияИБ <> "0.0.0.0"
И ОбщегоНазначения.РазделениеВключено()
И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
// Получение списка обработчиков сформированного на этапе выполнения неразделенных обработчиков.
ВыполняемыеОбработчики = ПолучитьПланОбновления(ИдентификаторБиблиотеки, ТекущаяВерсияИБ, ВерсияМетаданных);
Если ВыполняемыеОбработчики = Неопределено Тогда
Если ИтерацияОбновления.ЭтоОсновнаяКонфигурация Тогда
ШаблонСообщения = НСтр("ru = 'Не существует план обновления конфигурации %1 с версии %2 на версию %3'");
Иначе
ШаблонСообщения = НСтр("ru = 'Не существует план обновления библиотеки %1 с версии %2 на версию %3'");
КонецЕсли;
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, ИдентификаторБиблиотеки, ТекущаяВерсияИБ, ВерсияМетаданных);
ЗаписатьИнформацию(Сообщение);
ВыполняемыеОбработчики = ОбработчикиОбновленияВИнтервале(ОбработчикиОбновления, ТекущаяВерсияИБ, ВерсияМетаданных);
КонецЕсли;
Иначе
ВыполняемыеОбработчики = ОбработчикиОбновленияВИнтервале(ОбработчикиОбновления, ТекущаяВерсияИБ, ВерсияМетаданных);
КонецЕсли;
ОбязательныеРазделенныеОбработчики = ОбновлениеИнформационнойБазы.НоваяТаблицаОбработчиковОбновления();
ИсходнаяВерсияИБ = ТекущаяВерсияИБ;
ЗаписыватьВЖурнал = Константы.ДетализироватьОбновлениеИБВЖурналеРегистрации.Получить();
Для Каждого Версия Из ВыполняемыеОбработчики.Строки Цикл
Если Версия.Версия = "*" Тогда
Сообщение = НСтр("ru = 'Выполняются обязательные процедуры обновления информационной базы.'");
Иначе
НоваяВерсияИБ = Версия.Версия;
Если ТекущаяВерсияИБ = "0.0.0.0" Тогда
Сообщение = НСтр("ru = 'Выполняется начальное заполнение данных.'");
ИначеЕсли ИтерацияОбновления.ЭтоОсновнаяКонфигурация Тогда
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Выполняется обновление информационной базы с версии %1 на версию %2.'"),
ТекущаяВерсияИБ, НоваяВерсияИБ);
Иначе
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Выполняется обновление данных библиотеки %3 с версии %1 на версию %2.'"),
ТекущаяВерсияИБ, НоваяВерсияИБ, ИдентификаторБиблиотеки);
КонецЕсли;
КонецЕсли;
ЗаписатьИнформацию(Сообщение);
Для Каждого Обработчик Из Версия.Строки Цикл
ПараметрыОбработчика = Неопределено;
Если Обработчик.ВерсияРегистрации = "*" Тогда
Если Обработчик.УправлениеОбработчиками Тогда
ПараметрыОбработчика = Новый Структура;
ПараметрыОбработчика.Вставить("РазделенныеОбработчики", ОбязательныеРазделенныеОбработчики);
КонецЕсли;
Если Обработчик.МонопольныйРежим = Истина Или Обработчик.РежимВыполнения = "Монопольно" Тогда
Если Параметры.ОперативноеОбновление Тогда
// Проверки выполняются в ВозможноОперативноеОбновление, а само обновление для таких
// обработчиков выполняется только при неоперативном обновлении.
Продолжить;
КонецЕсли;
Если ПараметрыОбработчика = Неопределено Тогда
ПараметрыОбработчика = Новый Структура;
КонецЕсли;
ПараметрыОбработчика.Вставить("МонопольныйРежим", Истина);
КонецЕсли;
КонецЕсли;
ДополнительныеПараметры = Новый Структура;
ДополнительныеПараметры.Вставить("ЗаписыватьВЖурнал", ЗаписыватьВЖурнал);
ДополнительныеПараметры.Вставить("ИдентификаторБиблиотеки", ИдентификаторБиблиотеки);
ДополнительныеПараметры.Вставить("ХодВыполненияОбработчиков", Параметры.ХодВыполненияОбработчиков);
ДополнительныеПараметры.Вставить("ВФоне", Параметры.ВФоне);
ВыполнитьОбработчикОбновления(Обработчик, ПараметрыОбработчика, ДополнительныеПараметры);
КонецЦикла;
Если Версия.Версия = "*" Тогда
Сообщение = НСтр("ru = 'Выполнены обязательные процедуры обновления информационной базы.'");
ИначеЕсли СтрНачинаетсяС(Версия.Версия, "ОтладкаОбработчика") Тогда
Сообщение = НСтр("ru = 'Выполнены отлаживаемые процедуры обновления информационной базы.'");
Иначе
Если ИтерацияОбновления.ЭтоОсновнаяКонфигурация Тогда
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Выполнено обновление информационной базы с версии %1 на версию %2.'"),
ТекущаяВерсияИБ, НоваяВерсияИБ);
Иначе
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Выполнено обновление данных библиотеки %3 с версии %1 на версию %2.'"),
ТекущаяВерсияИБ, НоваяВерсияИБ, ИдентификаторБиблиотеки);
КонецЕсли;
КонецЕсли;
ЗаписатьИнформацию(Сообщение);
Если Версия.Версия <> "*" И Не СтрНачинаетсяС(Версия.Версия, "ОтладкаОбработчика") Тогда
// Установка номера версии информационной базы.
УстановитьВерсиюИБ(ИдентификаторБиблиотеки, НоваяВерсияИБ, ИтерацияОбновления.ЭтоОсновнаяКонфигурация);
ТекущаяВерсияИБ = НоваяВерсияИБ;
КонецЕсли;
КонецЦикла;
// Установка номера версии информационной базы.
ОтметитьРегистрациюДанных = Неопределено;
Если Параметры.Свойство("ОтметитьРегистрациюДанных") Тогда
ОтметитьРегистрациюДанных = Параметры.ОтметитьРегистрациюДанных;
КонецЕсли;
Если ВерсияИБ(ИдентификаторБиблиотеки) <> ВерсияМетаданныхИБ Тогда
УстановитьВерсиюИБ(ИдентификаторБиблиотеки, ВерсияМетаданныхИБ, ИтерацияОбновления.ЭтоОсновнаяКонфигурация, ОтметитьРегистрациюДанных);
КонецЕсли;
Если ТекущаяВерсияИБ <> "0.0.0.0" Тогда
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.СформироватьПланОбновленияОбластиДанных(ИдентификаторБиблиотеки, ОбработчикиОбновления,
ОбязательныеРазделенныеОбработчики, ИсходнаяВерсияИБ, ВерсияМетаданныхИБ);
КонецЕсли;
КонецЕсли;
Возврат ВыполняемыеОбработчики;
КонецФункции
////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.
// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииОбработчиковУстановкиПараметровСеанса.
Процедура ПриДобавленииОбработчиковУстановкиПараметровСеанса(Обработчики) Экспорт
Обработчики.Вставить("ВыполняетсяОбновлениеИБ", "ОбновлениеИнформационнойБазыСлужебный.УстановкаПараметровСеанса");
Обработчики.Вставить("ПараметрыОбработчикаОбновления", "ОбновлениеИнформационнойБазыСлужебный.УстановкаПараметровСеанса");
Обработчики.Вставить("ОтмененныеДлительныеОперации", "ДлительныеОперации.УстановкаПараметровСеанса");
КонецПроцедуры
// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииИсключенийПоискаСсылок.
Процедура ПриДобавленииИсключенийПоискаСсылок(ИсключенияПоискаСсылок) Экспорт
ИсключенияПоискаСсылок.Добавить(Метаданные.РегистрыСведений.ДанныеОбработанныеВЦентральномУзлеРИБ.ПолноеИмя());
КонецПроцедуры
// См. ЦентрМониторингаПереопределяемый.ПриСбореПоказателейСтатистикиКонфигурации.
Процедура ПриСбореПоказателейСтатистикиКонфигурации() Экспорт
Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЦентрМониторинга") Тогда
Возврат;
КонецЕсли;
МодульЦентрМониторинга = ОбщегоНазначения.ОбщийМодуль("ЦентрМониторинга");
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
Если СведенияОбОбновлении.ОтложенноеОбновлениеЗавершеноУспешно <> Истина Тогда
Возврат; // Получаем сведения только в том случае, когда отложенное обновление успешно завершилось.
КонецЕсли;
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Отложенно);
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.ИмяОбработчика КАК ИмяОбработчика,
| ОбработчикиОбновления.ДлительностьОбработки КАК ДлительностьОбработки
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.РежимВыполнения = &РежимВыполнения";
Обработчики = Запрос.Выполнить().Выгрузить();
Для Каждого Обработчик Из Обработчики Цикл
МодульЦентрМониторинга.ЗаписатьСтатистикуОбъектаКонфигурации("ВремяВыполненияОтложенногоОбработчика." + Обработчик.ИмяОбработчика, Обработчик.ДлительностьОбработки / 1000);
КонецЦикла;
ВремяНачала = СведенияОбОбновлении.ВремяНачалаОбновления;
ВремяОкончания = СведенияОбОбновлении.ВремяОкончанияОбновления;
Если ЗначениеЗаполнено(ВремяНачала) И ЗначениеЗаполнено(ВремяОкончания) Тогда
МодульЦентрМониторинга.ЗаписатьСтатистикуОбъектаКонфигурации("ВремяВыполненияОбработчиков",
ВремяОкончания - ВремяНачала);
КонецЕсли;
ВремяНачала = СведенияОбОбновлении.ВремяНачалаОтложенногоОбновления;
ВремяОкончания = СведенияОбОбновлении.ВремяОкончаниеОтложенногоОбновления;
Если ЗначениеЗаполнено(ВремяНачала) И ЗначениеЗаполнено(ВремяОкончания) Тогда
МодульЦентрМониторинга.ЗаписатьСтатистикуОбъектаКонфигурации("ВремяВыполненияОтложенныхОбработчиков",
ВремяОкончания - ВремяНачала);
КонецЕсли;
КонецПроцедуры
// См. СтандартныеПодсистемыСервер.ПриОтправкеДанныхПодчиненному.
Процедура ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза, Получатель) Экспорт
ПриОтправкеВерсийПодсистем(ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза);
КонецПроцедуры
// См. СтандартныеПодсистемыСервер.ПриОтправкеДанныхГлавному.
Процедура ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента, Получатель) Экспорт
ПриОтправкеВерсийПодсистем(ЭлементДанных, ОтправкаЭлемента);
КонецПроцедуры
// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииПараметровРаботыКлиентаПриЗапуске.
Процедура ПриДобавленииПараметровРаботыКлиентаПриЗапуске(Параметры) Экспорт
Параметры.Вставить("НачальноеЗаполнениеДанных", РежимОбновленияДанных() = "НачальноеЗаполнение");
Параметры.Вставить("ПоказатьОписаниеИзмененийСистемы", ПоказатьОписаниеИзмененийСистемы());
Если ОбщегоНазначения.РазделениеВключено() Тогда
Возврат;
КонецЕсли;
Если Пользователи.ЭтоПолноправныйПользователь(, Истина)
И Не ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы()
И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбновлениеКонфигурации") Тогда
Значение = ОбщегоНазначения.ХранилищеСистемныхНастроекЗагрузить("ПроверкаПатчей", "НомерВерсии");
Если Значение = Неопределено
Или ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Метаданные.Версия, Значение) > 0 Тогда
МодульОбновлениеКонфигурации = ОбщегоНазначения.ОбщийМодуль("ОбновлениеКонфигурации");
Результат = МодульОбновлениеКонфигурации.ИсправленияИзменены();
ОбщегоНазначения.ХранилищеСистемныхНастроекСохранить("ПроверкаПатчей", "НомерВерсии", Метаданные.Версия);
Если Результат.ЕстьИзменения Тогда
Сведения = СведенияОбОбновленииИнформационнойБазы();
Сведения.ВерсияУдалениеПатчей = Метаданные.Версия;
ЗаписатьСведенияОбОбновленииИнформационнойБазы(Сведения);
КонецЕсли;
КонецЕсли;
КонецЕсли;
СтатусОбработчиков = СтатусНевыполненныхОбработчиков();
Если СтатусОбработчиков = "" Тогда
Возврат;
КонецЕсли;
Если СтатусОбработчиков = "СтатусОшибка"
И Пользователи.ЭтоПолноправныйПользователь(, Истина) Тогда
Параметры.Вставить("ПоказатьСообщениеОбОшибочныхОбработчиках");
Иначе
Параметры.Вставить("ПоказатьОповещениеОНевыполненныхОбработчиках");
КонецЕсли;
КонецПроцедуры
// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления.
Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПроверкаЛегальностиПолученияОбновления") Тогда
Обработчик = Обработчики.Добавить();
Обработчик.НачальноеЗаполнение = Истина;
Обработчик.Процедура = "ОбновлениеИнформационнойБазыСлужебный.ЗаписатьПодтверждениеЛегальностиПолученияОбновлений";
КонецЕсли;
Если Не ОбщегоНазначения.РазделениеВключено() Тогда
Обработчик = Обработчики.Добавить();
Обработчик.Версия = "3.0.2.160";
Обработчик.Процедура = "ОбновлениеИнформационнойБазыСлужебный.УстановитьКлючРегламентногоЗадания";
Обработчик.РежимВыполнения = "Оперативно";
КонецЕсли;
КонецПроцедуры
// См. ОчередьЗаданийПереопределяемый.ПриПолученииСпискаШаблонов.
Процедура ПриПолученииСпискаШаблонов(ШаблоныЗаданий) Экспорт
ШаблоныЗаданий.Добавить("ОтложенноеОбновлениеИБ");
КонецПроцедуры
// Параметры:
// ТекущиеДела - см. ТекущиеДелаСервер.ТекущиеДела.
//
Процедура ПриЗаполненииСпискаТекущихДел(ТекущиеДела) Экспорт
МодульТекущиеДелаСервер = ОбщегоНазначения.ОбщийМодуль("ТекущиеДелаСервер");
Если Не Пользователи.ЭтоПолноправныйПользователь(, Истина)
Или МодульТекущиеДелаСервер.ДелоОтключено("ОтложенноеОбновление") Тогда
Возврат;
КонецЕсли;
Если ОбщегоНазначения.РазделениеВключено() Тогда
Возврат;
КонецЕсли;
// Процедура вызывается только при наличии подсистемы "Текущие дела", поэтому здесь
// не делается проверка существования подсистемы.
Разделы = МодульТекущиеДелаСервер.РазделыДляОбъекта(Метаданные.Обработки.РезультатыОбновленияПрограммы.ПолноеИмя());
СтатусОбработчиков = СтатусНевыполненныхОбработчиков();
ЕстьОбработчикиСОшибкой = (СтатусОбработчиков = "СтатусОшибка");
ЕстьНеВыполненныеОбработчики = (СтатусОбработчиков = "СтатусНеВыполнено");
ЕстьПриостановленныеОбработчики = (СтатусОбработчиков = "СтатусПриостановлен");
Для Каждого Раздел Из Разделы Цикл
Идентификатор = "ОтложенноеОбновление" + СтрЗаменить(Раздел.ПолноеИмя(), ".", "");
Дело = ТекущиеДела.Добавить();
Дело.Идентификатор = Идентификатор;
Дело.ЕстьДела = (ЕстьОбработчикиСОшибкой Или ЕстьНеВыполненныеОбработчики Или ЕстьПриостановленныеОбработчики);
Дело.Важное = ЕстьОбработчикиСОшибкой;
Дело.Представление = НСтр("ru = 'Обновление программы не завершено'");
Дело.Форма = "Обработка.РезультатыОбновленияПрограммы.Форма.РезультатыОбновленияПрограммы";
Дело.Владелец = Раздел;
КонецЦикла;
КонецПроцедуры
// См. ВариантыОтчетовПереопределяемый.НастроитьВариантыОтчетов.
Процедура ПриНастройкеВариантовОтчетов(Настройки) Экспорт
МодульВариантыОтчетов = ОбщегоНазначения.ОбщийМодуль("ВариантыОтчетов");
МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.ПрогрессОтложенногоОбновления);
КонецПроцедуры
// Перезапускает отложенные обработчики, выполняющиеся только в главном узле
// при получении первого сообщения обмена.
//
Процедура ПриПолученииПервогоСообщенияОбменаРИБПослеОбновления() Экспорт
УстановитьПривилегированныйРежим(Истина);
ИнформационнаяБазаФайловая = ОбщегоНазначения.ИнформационнаяБазаФайловая();
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
Если СведенияОбОбновлении.ОтложенноеОбновлениеЗавершеноУспешно = Неопределено
И Не ИнформационнаяБазаФайловая Тогда
ОтключитьОтложенноеОбновление();
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("ИмяМетода", "ОбновлениеИнформационнойБазыСлужебный.ВыполнитьОтложенноеОбновление");
ПараметрыОтбора.Вставить("Состояние", СостояниеФоновогоЗадания.Активно);
МассивФоновыхЗаданий = ФоновыеЗадания.ПолучитьФоновыеЗадания(ПараметрыОтбора);
Если МассивФоновыхЗаданий.Количество() = 1 Тогда
ФоновоеЗадание = МассивФоновыхЗаданий[0];
ФоновоеЗадание.Отменить();
КонецЕсли;
КонецЕсли;
ИтерацииОбновления = ИтерацииОбновления();
Обработки.ОписаниеОбработчиковОбновления.ЗаполнитьНомерОчереди(ИтерацииОбновления);
ОбновитьСписокВыполняемыхОбработчиковОбновления(ИтерацииОбновления, Истина);
ПеререгистрироватьДанныеДляОтложенногоОбновления();
Если ИнформационнаяБазаФайловая Тогда
ВыполнитьОтложенноеОбновлениеСейчас();
Иначе
ЗапланироватьОтложенноеОбновление();
КонецЕсли;
КонецПроцедуры
// Вызывается при выполнении скрипта обновления из процедуры ОбновлениеКонфигурации.ЗавершитьОбновление.
Процедура ПослеЗавершенияОбновления() Экспорт
ЗаписатьПодтверждениеЛегальностиПолученияОбновлений();
КонецПроцедуры
// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПослеЗагрузкиДанных.
Процедура ПослеЗагрузкиДанных(Контейнер) Экспорт
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
Если СведенияОбОбновлении.ОтложенноеОбновлениеЗавершеноУспешно <> Истина Тогда
ЗапланироватьОтложенноеОбновление();
КонецЕсли;
КонецПроцедуры
// См. ПодключаемыеКомандыПереопределяемый.ПриОпределенииКомандПодключенныхКОбъекту
Процедура ПриОпределенииКомандПодключенныхКОбъекту(НастройкиФормы, Источники, ПодключенныеОтчетыИОбработки, Команды) Экспорт
Команда = Команды.Добавить();
Команда.Вид = "ОбновлениеВерсииИБ";
Команда.Представление = НСтр("ru = 'Разблокировать объект для редактирования'");
Команда.РежимЗаписи = "НеЗаписывать";
Команда.Назначение = "ДляОбъекта";
Команда.ТолькоВоВсехДействиях = Истина;
Команда.Обработчик = "ОбновлениеИнформационнойБазыКлиент.РазблокироватьОбъектДляРедактирования";
МодульПодключаемыеКоманды = ОбщегоНазначения.ОбщийМодуль("ПодключаемыеКоманды");
МодульПодключаемыеКоманды.ДобавитьУсловиеВидимостиКоманды(Команда, "ОбновлениеВерсииИБ_ОбъектЗаблокирован");
КонецПроцедуры
// См. ПодключаемыеКомандыПереопределяемый.ПриОпределенииВидовПодключаемыхКоманд
Процедура ПриОпределенииВидовПодключаемыхКоманд(ВидыПодключаемыхКоманд) Экспорт
Вид = ВидыПодключаемыхКоманд.Добавить();
Вид.Имя = "ОбновлениеВерсииИБ";
Вид.Заголовок = НСтр("ru = 'Разблокировка объекта'");
Вид.Отображение = ОтображениеКнопки.КартинкаИТекст;
КонецПроцедуры
// См. ОчередьЗаданийПереопределяемый.ПриОпределенииПсевдонимовОбработчиков.
Процедура ПриОпределенииПсевдонимовОбработчиков(СоответствиеИменПсевдонимам) Экспорт
СоответствиеИменПсевдонимам.Вставить("ОбновлениеИнформационнойБазы.ПерезапуститьОтложенноеОбновление");
КонецПроцедуры
// См. КонтрольВеденияУчетаПереопределяемый.ПриОпределенииПроверок.
Процедура ПриОпределенииПроверок(ГруппыПроверок, Проверки) Экспорт
Проверка = Проверки.Добавить();
Проверка.ИдентификаторГруппы = "СистемныеПроверки";
Проверка.Наименование = НСтр("ru = 'Проблема с данными при обновлении на новую версию'");
Проверка.Причины = НСтр("ru = 'Некорректная синхронизация данных с другими программами или импорт данных,
|ошибки в сторонних инструментах (например, внешних обработках или расширениях) или сбои в работе оборудования.'");
Проверка.Рекомендация = НСтр("ru = 'Если не заполнены обязательные реквизиты, то заполнить их вручную.
|Восстановить отсутствующие данные из резервной копии.'");
Проверка.Идентификатор = "ОбновлениеИнформационнойБазыПроблемаСДанными";
Проверка.ОбработчикПроверки = "ОбновлениеИнформационнойБазыСлужебный.ОбработчикПроверкиВеденияУчета";
Проверка.ЗапрещеноИзменениеВажности = Ложь;
Проверка.КонтекстПроверокВеденияУчета = "ОбновлениеВерсииИБ";
Проверка.Отключена = Истина;
КонецПроцедуры
Функция НастройкиПодсистемы() Экспорт
ПараметрыСообщенияОНевыполненныхОтложенныхОбработчиках = Новый Структура;
ПараметрыСообщенияОНевыполненныхОтложенныхОбработчиках.Вставить("ТекстСообщения", "");
ПараметрыСообщенияОНевыполненныхОтложенныхОбработчиках.Вставить("КартинкаСообщения", Неопределено);
ПараметрыСообщенияОНевыполненныхОтложенныхОбработчиках.Вставить("ЗапрещатьПродолжение", Ложь);
Настройки = Новый Структура;
Настройки.Вставить("ПоясненияДляРезультатовОбновления", "");
Настройки.Вставить("РасположениеОписанияИзмененийПрограммы", "");
Настройки.Вставить("ПараметрыСообщенияОНевыполненныхОтложенныхОбработчиках", ПараметрыСообщенияОНевыполненныхОтложенныхОбработчиках);
Настройки.Вставить("МногопоточноеОбновление", Ложь);
Настройки.Вставить("КоличествоПотоковОбновленияИнформационнойБазыПоУмолчанию", 1);
Настройки.Вставить("ОбъектыСНачальнымЗаполнением", Новый Массив);
ИнтеграцияПодсистемБСП.ПриОпределенииОбъектовСНачальнымЗаполнением(Настройки.ОбъектыСНачальнымЗаполнением);
ОбновлениеИнформационнойБазыПереопределяемый.ПриОпределенииНастроек(Настройки);
Возврат Настройки;
КонецФункции
// Начальное заполнение предопределенных данных
// Возвращаемое значение:
// Массив из ОбъектМетаданных
//
Функция ОбъектыСНачальнымЗаполнением() Экспорт
НастройкиПодсистемы = НастройкиПодсистемы();
ОбъектыСНачальнымЗаполнением = НастройкиПодсистемы.ОбъектыСНачальнымЗаполнением;
Возврат ОбъектыСНачальнымЗаполнением;
КонецФункции
Функция НастройкиПредопределенныхЭлементов(МенеджерОбъекта, ПредопределенныеДанные) Экспорт
ПользовательскиеНастройкиЗаполненияЭлементов = ПользовательскиеНастройкиЗаполненияЭлементов();
ПользовательскиеНастройкиЗаполненияЭлементов.ДополнительныеПараметры.Вставить("ПредопределенныеДанные", ПредопределенныеДанные);
ПолноеИмяОбъекта = МенеджерОбъекта.ПустаяСсылка().Метаданные().ПолноеИмя();
МенеджерОбъекта.ПриНастройкеНачальногоЗаполненияЭлементов(ПользовательскиеНастройкиЗаполненияЭлементов);
ОбновлениеИнформационнойБазыПереопределяемый.ПриНастройкеНачальногоЗаполненияЭлементов(ПолноеИмяОбъекта,
ПользовательскиеНастройкиЗаполненияЭлементов);
НастройкиЗаполненияЭлементов = НастройкиЗаполненияЭлементов();
ЗаполнитьЗначенияСвойств(НастройкиЗаполненияЭлементов.ПереопределяемыеНастройки, ПользовательскиеНастройкиЗаполненияЭлементов);
НастройкиЗаполненияЭлементов.ЕстьКолонкаИмяПредопределенныхДанных =
ПредопределенныеДанные.Колонки.Найти("ИмяПредопределенныхДанных") <> Неопределено;
НастройкиЗаполненияЭлементов.ПереопределяемыеНастройки.ИмяКлючевогоРеквизита =
?(ЗначениеЗаполнено(НастройкиЗаполненияЭлементов.ПереопределяемыеНастройки.ИмяКлючевогоРеквизита),
НастройкиЗаполненияЭлементов.ПереопределяемыеНастройки.ИмяКлючевогоРеквизита, "ИмяПредопределенныхДанных");
Возврат НастройкиЗаполненияЭлементов;
КонецФункции
// Описание настроек заполнения элементов
//
// Возвращаемое значение:
// Структура:
// * ПереопределяемыеНастройки - см. ПользовательскиеНастройкиЗаполненияЭлементов
// * ЕстьКолонкаИмяПредопределенныхДанных - Булево
//
Функция НастройкиЗаполненияЭлементов() Экспорт
НастройкиЗаполненияЭлементов = Новый Структура;
НастройкиЗаполненияЭлементов.Вставить("ПереопределяемыеНастройки", ПользовательскиеНастройкиЗаполненияЭлементов());
НастройкиЗаполненияЭлементов.Вставить("ЕстьКолонкаИмяПредопределенныхДанных", Ложь);
Возврат НастройкиЗаполненияЭлементов;
КонецФункции
Функция ПредопределенныеДанныеОбъекта(Знач МетаданныеОбъекта, МенеджерОбъекта, ЛокализуемыеРеквизитыОбъекта) Экспорт
Языки = СтандартныеПодсистемыСервер.ЯзыкиКонфигурации();
// Таблица с предопределенными данными
ПредопределенныеДанные = Новый ТаблицаЗначений;
ТабличныеЧасти = Новый Структура;
Для Каждого Реквизит Из МетаданныеОбъекта.СтандартныеРеквизиты Цикл
ДобавитьКолонкуТаблицыПредопределенныхДанных(ПредопределенныеДанные, Реквизит, ЛокализуемыеРеквизитыОбъекта, Языки);
КонецЦикла;
Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
ДобавитьКолонкуТаблицыПредопределенныхДанных(ПредопределенныеДанные, Реквизит, ЛокализуемыеРеквизитыОбъекта, Языки);
КонецЦикла;
Для Каждого ТабличнаяЧасть Из МетаданныеОбъекта.ТабличныеЧасти Цикл
ПредопределенныеДанные.Колонки.Добавить(ТабличнаяЧасть.Имя, Новый ОписаниеТипов("ТаблицаЗначений"));
Таблица = Новый ТаблицаЗначений;
Для Каждого Реквизит Из ТабличнаяЧасть.СтандартныеРеквизиты Цикл
ДобавитьКолонкуТаблицыПредопределенныхДанных(Таблица, Реквизит, ЛокализуемыеРеквизитыОбъекта, Языки);
КонецЦикла;
Для Каждого Реквизит Из ТабличнаяЧасть.Реквизиты Цикл
ДобавитьКолонкуТаблицыПредопределенныхДанных(Таблица, Реквизит, ЛокализуемыеРеквизитыОбъекта, Языки);
КонецЦикла;
ТабличныеЧасти.Вставить(ТабличнаяЧасть.Имя, Таблица);
КонецЦикла;
Если ОбщегоНазначения.ЭтоПланСчетов(МетаданныеОбъекта)
Или ОбщегоНазначения.ЭтоПланВидовРасчета(МетаданныеОбъекта) Тогда
Для Каждого ТабличнаяЧасть Из МетаданныеОбъекта.СтандартныеТабличныеЧасти Цикл
ПредопределенныеДанные.Колонки.Добавить(ТабличнаяЧасть.Имя, Новый ОписаниеТипов("ТаблицаЗначений"));
Таблица = Новый ТаблицаЗначений;
Для Каждого Реквизит Из ТабличнаяЧасть.СтандартныеРеквизиты Цикл
ДобавитьКолонкуТаблицыПредопределенныхДанных(Таблица, Реквизит, ЛокализуемыеРеквизитыОбъекта, Языки);
КонецЦикла;
ТабличныеЧасти.Вставить(ТабличнаяЧасть.Имя, Таблица);
КонецЦикла;
КонецЕсли;
Если ПредопределенныеДанные.Колонки.Найти("ИмяПредопределенныхДанных") <> Неопределено Тогда
ПредопределенныеДанные.Индексы.Добавить("ИмяПредопределенныхДанных");
КонецЕсли;
МенеджерОбъекта.ПриНачальномЗаполненииЭлементов(Языки, ПредопределенныеДанные, ТабличныеЧасти);
ОбновлениеИнформационнойБазыПереопределяемый.ПриНачальномЗаполненииЭлементов(МетаданныеОбъекта.ПолноеИмя(), Языки, ПредопределенныеДанные, ТабличныеЧасти);
Если ПредопределенныеДанные.Колонки.Найти("Ссылка") <> Неопределено Тогда
Для Каждого СтрокаПредопределенныхДанных Из ПредопределенныеДанные Цикл
Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Если ТипЗнч(СтрокаПредопределенныхДанных.Ссылка) = Тип("УникальныйИдентификатор") Тогда
СтрокаПредопределенныхДанных.Ссылка = МенеджерОбъекта.ПолучитьСсылку(СтрокаПредопределенныхДанных.Ссылка);
ИначеЕсли ТипЗнч(СтрокаПредопределенныхДанных.Ссылка) = Тип("Строка") Тогда
СтрокаПредопределенныхДанных.Ссылка = МенеджерОбъекта.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаПредопределенныхДанных.Ссылка));
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Возврат ПредопределенныеДанные;
КонецФункции
// Параметры:
// ОбновитьМультиязычныеСтроки - Булево - если Истина, то будут перезаполнены, только мультиязычные реквизиты.
// ДополнительныеПараметры - см. МультиязычностьСервер.ОписаниеСтарыхИНовыхНастроекЯзыков
//
Процедура НачальноеЗаполнениеПредопределенныхДанных(ОбновитьМультиязычныеСтроки = Ложь, ДополнительныеПараметры = Неопределено) Экспорт
ОбъектыСНачальнымЗаполнением = ОбъектыСНачальнымЗаполнением();
ПараметрыЗаполнения = Новый Структура;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
МодульМультиязычностьСервер.ПриПолученииПараметровЗаполненияПредопределенныхДанных(ПараметрыЗаполнения);
КонецЕсли;
ПроверятьНеобходимостьВыполнения = ДополнительныеПараметры <> Неопределено
И ТипЗнч(ДополнительныеПараметры) = Тип("Структура")
И ДополнительныеПараметры.Свойство("НовыеОбъекты");
Для Каждого МетаданныеОбъекта Из ОбъектыСНачальнымЗаполнением Цикл
Если ПроверятьНеобходимостьВыполнения
И ДополнительныеПараметры.НовыеОбъекты.Найти(МетаданныеОбъекта.ПолноеИмя()) = Неопределено Тогда
Продолжить;
КонецЕсли;
ПараметрыЗаполнения = НаборПараметровДляЗаполненияОбъекта(МетаданныеОбъекта);
МенеджерОбъекта = ПараметрыЗаполнения.МенеджерОбъекта;
ПредопределенныеДанные = ПараметрыЗаполнения.ПредопределенныеДанные;
НастройкиЗаполнения = ПараметрыЗаполнения.НастройкиПредопределенныхЭлементов;
ИмяКлючевогоРеквизита = НастройкиЗаполнения.ПереопределяемыеНастройки.ИмяКлючевогоРеквизита;
СуществующиеЭлементы = СуществующиеПоставляемыеЭлементы(ПредопределенныеДанные, НастройкиЗаполнения, МенеджерОбъекта, МетаданныеОбъекта);
ТабличныеЧасти = Новый Массив;
ОбъектМетаданныхТабличныеЧасти = МетаданныеОбъекта.ТабличныеЧасти; // КоллекцияОбъектовМетаданных из ОбъектМетаданныхТабличнаяЧасть
Для Каждого ТабличнаяЧасть Из ОбъектМетаданныхТабличныеЧасти Цикл
Если ПредопределенныеДанные.Колонки.Найти(ТабличнаяЧасть.Имя) <> Неопределено Тогда
ТабличныеЧасти.Добавить(ТабличнаяЧасть.Имя);
КонецЕсли;
КонецЦикла;
РеквизитыИсключения = Новый Соответствие;
Если СтрНачинаетсяС(МетаданныеОбъекта.ПолноеИмя(), "ПланВидовХарактеристик") Тогда
РеквизитыИсключения.Вставить("ТипЗначения", Истина);
КонецЕсли;
ПоддерживаетсяИерархия = ПредопределенныеДанные.Колонки.Найти("ЭтоГруппа") <> Неопределено;
РеквизитыИсключения.Вставить("Родитель", Истина); // Поле заполняется отдельно
РеквизитыИсключенияСЭлементами = Новый Соответствие;
Если ПоддерживаетсяИерархия Тогда
ОбщегоНазначенияКлиентСервер.ДополнитьСоответствие(РеквизитыИсключенияСЭлементами, РеквизитыИсключения);
ДляЭлемента = Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляЭлемента;
Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
Если Реквизит.Использование = ДляЭлемента Тогда
РеквизитыИсключенияСЭлементами.Вставить(Реквизит.Имя, Истина);
КонецЕсли;
КонецЦикла;
КонецЕсли;
ЕстьКолонкаСсылка = ПредопределенныеДанные.Колонки.Найти("Ссылка") <> Неопределено;
НачатьТранзакцию();
Попытка
Для каждого СтрокаТаблицы Из ПредопределенныеДанные Цикл
СсылкаНаОбъект = Неопределено;
Если НастройкиЗаполнения.ЕстьКолонкаИмяПредопределенныхДанных Тогда
СсылкаНаОбъект = СуществующиеЭлементы[СтрокаТаблицы.ИмяПредопределенныхДанных];
КонецЕсли;
Если СсылкаНаОбъект = Неопределено И ЗначениеЗаполнено(СтрокаТаблицы[ИмяКлючевогоРеквизита]) Тогда
СсылкаНаОбъект = СуществующиеЭлементы[СтрокаТаблицы[ИмяКлючевогоРеквизита]];
КонецЕсли;
Если СсылкаНаОбъект <> Неопределено Тогда
БлокировкаДанных = Новый БлокировкаДанных;
ЭлементБлокировкиДанных = БлокировкаДанных.Добавить(МетаданныеОбъекта.ПолноеИмя());
ЭлементБлокировкиДанных.УстановитьЗначение("Ссылка", СсылкаНаОбъект);
БлокировкаДанных.Заблокировать();
ЗаполняемыйЭлемент = СсылкаНаОбъект.ПолучитьОбъект();
Иначе
Если ПоддерживаетсяИерархия И СтрокаТаблицы.ЭтоГруппа = Истина Тогда
ЗаполняемыйЭлемент = МенеджерОбъекта.СоздатьГруппу();
Иначе
ЗаполняемыйЭлемент = МенеджерОбъекта.СоздатьЭлемент();
КонецЕсли;
Если ЕстьКолонкаСсылка И ЗначениеЗаполнено(СтрокаТаблицы.Ссылка) Тогда
ЗаполняемыйЭлемент.УстановитьСсылкуНового(СтрокаТаблицы.Ссылка);
Если ЗначениеЗаполнено(СтрокаТаблицы[ИмяКлючевогоРеквизита]) Тогда
СуществующиеЭлементы.Вставить(СтрокаТаблицы[ИмяКлючевогоРеквизита], СтрокаТаблицы.Ссылка);
КонецЕсли;
Иначе
НоваяСсылка = МенеджерОбъекта.ПолучитьСсылку();
ЗаполняемыйЭлемент.УстановитьСсылкуНового(НоваяСсылка);
Если ЗначениеЗаполнено(СтрокаТаблицы[ИмяКлючевогоРеквизита]) Тогда
СуществующиеЭлементы.Вставить(СтрокаТаблицы[ИмяКлючевогоРеквизита], НоваяСсылка);
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если Не ОбновитьМультиязычныеСтроки Тогда
Если ПоддерживаетсяИерархия И ЗначениеЗаполнено(СтрокаТаблицы.Родитель) Тогда
Если ИмяКлючевогоРеквизита = "Ссылка" Тогда
Если ТипЗнч(СтрокаТаблицы.Родитель) = Тип("Строка") Тогда
ЗаполняемыйЭлемент.Родитель = МенеджерОбъекта.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаТаблицы.Родитель));
ИначеЕсли ТипЗнч(СтрокаТаблицы.Родитель) = Тип("УникальныйИдентификатор") Тогда
ЗаполняемыйЭлемент.Родитель = МенеджерОбъекта.ПолучитьСсылку(СтрокаТаблицы.Родитель);
Иначе
ЗаполняемыйЭлемент.Родитель = СтрокаТаблицы.Родитель;
КонецЕсли;
ИначеЕсли ТипЗнч(СтрокаТаблицы.Родитель) = Тип("Строка") Тогда
ЗаполняемыйЭлемент.Родитель = СуществующиеЭлементы[СтрокаТаблицы.Родитель];
Иначе
ЗаполняемыйЭлемент.Родитель = СтрокаТаблицы.Родитель;
КонецЕсли;
КонецЕсли;
ПоляИсключения =?(ПоддерживаетсяИерархия И ЗаполняемыйЭлемент.ЭтоГруппа,
РеквизитыИсключенияСЭлементами, РеквизитыИсключения);
ДанныеЗаполнения = ОпределитьДанныеЗаполнения(ПредопределенныеДанные, СтрокаТаблицы, ПоляИсключения);
ЗаполнитьЗначенияСвойств(ЗаполняемыйЭлемент, ДанныеЗаполнения);
Если Не (ПоддерживаетсяИерархия И ЗаполняемыйЭлемент.ЭтоГруппа) Тогда
Для Каждого ИмяТабличнойЧасти Из ТабличныеЧасти Цикл
Если СтрокаТаблицы[ИмяТабличнойЧасти].Количество() > 0 Тогда
ЗаполняемыйЭлемент[ИмяТабличнойЧасти].Загрузить(СтрокаТаблицы[ИмяТабличнойЧасти]);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
Если ПараметрыЗаполнения.ЛокализуемыеРеквизитыОбъекта.Количество() > 0 И ПараметрыЗаполнения.ЛокализуемыеРеквизитыОбъекта["Наименование"] <> Неопределено Тогда
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
МодульМультиязычностьСервер.НачальноеЗаполнениеПредопределенныхДанныхЛокализуемыеРеквизиты(
ЗаполняемыйЭлемент, ПоддерживаетсяИерархия, СтрокаТаблицы, ПараметрыЗаполнения);
ИначеЕсли ПараметрыЗаполнения.ОбъектСодержитТЧПредставления Тогда
НачальноеЗаполнениеТЧПредставления(ЗаполняемыйЭлемент, СтрокаТаблицы, ПараметрыЗаполнения);
КонецЕсли;
ИначеЕсли ОбновитьМультиязычныеСтроки
И ПредопределенныеДанные.Колонки.Найти("Наименование") <> Неопределено
И ЗначениеЗаполнено(СтрокаТаблицы["Наименование"]) Тогда
ЗаполняемыйЭлемент["Наименование"] = СтрокаТаблицы["Наименование"];
КонецЕсли;
Если Не ОбновитьМультиязычныеСтроки И НастройкиЗаполнения.ПереопределяемыеНастройки.ПриНачальномЗаполненииЭлемента Тогда
МенеджерОбъекта.ПриНачальномЗаполненииЭлемента(ЗаполняемыйЭлемент, СтрокаТаблицы, НастройкиЗаполнения.ПереопределяемыеНастройки.ДополнительныеПараметры);
ОбновлениеИнформационнойБазыПереопределяемый.ПриНачальномЗаполненииЭлемента(МетаданныеОбъекта.ПолноеИмя(),
ЗаполняемыйЭлемент, СтрокаТаблицы, НастройкиЗаполнения.ПереопределяемыеНастройки.ДополнительныеПараметры);
КонецЕсли;
ОбновлениеИнформационнойБазы.ЗаписатьОбъект(ЗаполняемыйЭлемент);
СтрокаТаблицы.Ссылка = ЗаполняемыйЭлемент.Ссылка;
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонецЦикла;
Если ОбновитьМультиязычныеСтроки Тогда
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
МодульУправлениеДоступомСлужебный = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступомСлужебный");
МодульУправлениеДоступомСлужебный.ПриИзмененииЯзыкаИнформационнойБазы(ДополнительныеПараметры);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура НачальноеЗаполнениеТЧПредставления(ЗаполняемыйЭлемент, СтрокаТаблицы, ПараметрыЗаполнения) Экспорт
Языки = СтандартныеПодсистемыСервер.ЯзыкиКонфигурации();
ЛокализуемыеРеквизитыОбъекта = ПараметрыЗаполнения.ЛокализуемыеРеквизитыОбъекта;
Для каждого КодЯзыка Из Языки Цикл
Если СтрСравнить(КодЯзыка, ОбщегоНазначения.КодОсновногоЯзыка()) = 0 Тогда
Продолжить;
КонецЕсли;
ПредставленияОбъекта = ЗаполняемыйЭлемент.Представления; // ТаблицаЗначений
НовоеПредставление = ПредставленияОбъекта.Добавить();
НовоеПредставление.КодЯзыка = КодЯзыка;
Для каждого ИмяЛокализуемогоРеквизита Из ЛокализуемыеРеквизитыОбъекта Цикл
Значение = СтрокаТаблицы[ИмяЛокализуемогоРеквизита.Ключ + "_" + КодЯзыка];
НовоеПредставление[ИмяЛокализуемогоРеквизита.Ключ] = ?(ЗначениеЗаполнено(Значение), Значение, СтрокаТаблицы[ИмяЛокализуемогоРеквизита.Ключ]);
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Функция НаборПараметровДляЗаполненияОбъекта(МетаданныеОбъекта) Экспорт
Результат = Новый Структура;
ОбъектыСНачальнымЗаполнением = ОбъектыСНачальнымЗаполнением();
ЕстьПредопределенныеДанные = ОбъектыСНачальнымЗаполнением.Найти(МетаданныеОбъекта) <> Неопределено;
ЛокализуемыеРеквизитыОбъекта = Новый Соответствие;
МультиязычныеСтрокиВРеквизитах = Ложь;
ОбъектСодержитТЧПредставления = Ложь;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
ЛокализуемыеРеквизитыОбъекта = МодульМультиязычностьСервер.МультиязычныеРеквизитыОбъекта(МетаданныеОбъекта);
МультиязычныеСтрокиВРеквизитах = МодульМультиязычностьСервер.МультиязычныеСтрокиВРеквизитах(МетаданныеОбъекта);
ОбъектСодержитТЧПредставления = МодульМультиязычностьСервер.ОбъектСодержитТЧПредставления(МетаданныеОбъекта.ПолноеИмя());
КонецЕсли;
МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(МетаданныеОбъекта.ПолноеИмя());
Если ЕстьПредопределенныеДанные Тогда
ПредопределенныеДанные = ПредопределенныеДанныеОбъекта(МетаданныеОбъекта, МенеджерОбъекта, ЛокализуемыеРеквизитыОбъекта);
НастройкиПредопределенныхЭлементов = НастройкиПредопределенныхЭлементов(МенеджерОбъекта, ПредопределенныеДанные);
Иначе
ПредопределенныеДанные = Новый ТаблицаЗначений();
НастройкиПредопределенныхЭлементов = Новый Структура;
КонецЕсли;
ТабличныеЧасти = Новый Массив;
ОбъектМетаданныхТабличныеЧасти = МетаданныеОбъекта.ТабличныеЧасти; // КоллекцияОбъектовМетаданных из ОбъектМетаданныхТабличнаяЧасть
Для Каждого ТабличнаяЧасть Из ОбъектМетаданныхТабличныеЧасти Цикл
Если ПредопределенныеДанные.Колонки.Найти(ТабличнаяЧасть.Имя) <> Неопределено Тогда
ТабличныеЧасти.Добавить(ТабличнаяЧасть.Имя);
КонецЕсли;
КонецЦикла;
РеквизитыИсключения = ?(СтрНачинаетсяС(МетаданныеОбъекта.ПолноеИмя(), "ПланВидовХарактеристик"), "ТипЗначения", "");
ПоддерживаетсяИерархия = ПредопределенныеДанные.Колонки.Найти("ЭтоГруппа") <> Неопределено;
ТЧПредставленияИспользуетсяДляГрупп = Ложь;
Если ОбъектСодержитТЧПредставления И ПоддерживаетсяИерархия Тогда
Если МетаданныеОбъекта.ТабличныеЧасти.Представления.Использование = Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляГруппыИЭлемента
Или МетаданныеОбъекта.ТабличныеЧасти.Представления.Использование = Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляГруппы Тогда
ТЧПредставленияИспользуетсяДляГрупп = Истина;
КонецЕсли;
КонецЕсли;
РеквизитыСЭлементами = Новый Массив;
Если ПоддерживаетсяИерархия Тогда
ДляЭлемента = Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляЭлемента;
Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
Если Реквизит.Использование = ДляЭлемента Тогда
РеквизитыСЭлементами.Добавить(Реквизит.Имя);
КонецЕсли;
КонецЦикла;
КонецЕсли;
Результат.Вставить("НастройкиПредопределенныхЭлементов", НастройкиПредопределенныхЭлементов);
Результат.Вставить("ПредопределенныеДанные", ПредопределенныеДанные);
Результат.Вставить("РеквизитыИсключения", РеквизитыИсключения);
Результат.Вставить("ПоддерживаетсяИерархия", ПоддерживаетсяИерархия);
Результат.Вставить("ТабличныеЧасти", ТабличныеЧасти);
Результат.Вставить("ЛокализуемыеРеквизитыОбъекта", ЛокализуемыеРеквизитыОбъекта);
Результат.Вставить("МультиязычныеСтрокиВРеквизитах", МультиязычныеСтрокиВРеквизитах);
Результат.Вставить("ОбъектСодержитТЧПредставления", ОбъектСодержитТЧПредставления);
Результат.Вставить("ТЧПредставленияИспользуетсяДляГрупп", ТЧПредставленияИспользуетсяДляГрупп);
Результат.Вставить("МенеджерОбъекта", МенеджерОбъекта);
Результат.Вставить("РеквизитыСЭлементами", РеквизитыСЭлементами);
Возврат Результат;
КонецФункции
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
Функция ОпределитьДанныеЗаполнения(Знач ПредопределенныеДанные, Знач СтрокаТаблицы, Знач ПоляИсключения)
ДанныеЗаполнения = Новый Структура;
Для Каждого Колонка Из ПредопределенныеДанные.Колонки Цикл
ИмяПоля = Колонка.Имя;
Если ПоляИсключения[ИмяПоля] = Истина Тогда
Продолжить;
КонецЕсли;
Значение = СтрокаТаблицы[ИмяПоля];
Если Колонка.ТипЗначения.Типы().Количество() > 1 Тогда
Заполнено = Значение <> Неопределено;
ИначеЕсли ТипЗнч(Значение) = Тип("Булево") Тогда
Заполнено = Значение;
Иначе
Заполнено = ЗначениеЗаполнено(Значение);
КонецЕсли;
Если Заполнено Тогда
ДанныеЗаполнения.Вставить(ИмяПоля, Значение);
КонецЕсли;
КонецЦикла;
Возврат ДанныеЗаполнения;
КонецФункции
Функция ДействияПередОбновлениемИнформационнойБазы(ПараметрыОбновления)
Если Не ПараметрыОбновления.ПриЗапускеКлиентскогоПриложения Тогда
Если Не ОбщегоНазначения.РазделениеВключено()
И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбновлениеКонфигурации") Тогда
МодульОбновлениеКонфигурации = ОбщегоНазначения.ОбщийМодуль("ОбновлениеКонфигурации");
МодульОбновлениеКонфигурации.ПроверитьНаличиеУстаревшихИсправлений();
КонецЕсли;
Попытка
РегистрыСведений.ПараметрыРаботыПрограммы.ЗагрузитьОбновитьПараметрыРаботыПрограммы();
Исключение
ЗаписатьОшибку(ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение;
КонецПопытки;
КонецЕсли;
Результат = Новый Структура;
Результат.Вставить("Возврат", "");
// Определяем факт смены имени конфигурации.
РежимОбновленияДанных = РежимОбновленияДанных();
ВерсияМетаданных = Метаданные.Версия;
Если ПустаяСтрока(ВерсияМетаданных) Тогда
ВерсияМетаданных = "0.0.0.0";
КонецЕсли;
ВерсияДанных = ВерсияИБ(Метаданные.Имя);
// Перед обновлением информационной базы.
//
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.ПередОбновлениемИнформационнойБазы();
// Установка привилегированного режима для возможности обновления ИБ в модели сервиса,
// в случае когда администратор области данных выполняет вход в область до завершения обновления области.
Если ОбщегоНазначения.РазделениеВключено() И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
УстановитьПривилегированныйРежим(Истина);
КонецЕсли;
КонецЕсли;
// Загрузка и выгрузка сообщения обмена после перезапуска в связи с получением изменений конфигурации.
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда
МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер");
МодульОбменДаннымиСервер.ПередОбновлениемИнформационнойБазы(ПараметрыОбновления.ПриЗапускеКлиентскогоПриложения, ПараметрыОбновления.Перезапустить);
КонецЕсли;
Если НЕ ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы() Тогда
Результат.Возврат = "НеТребуется";
Возврат Результат;
КонецЕсли;
Если ПараметрыОбновления.ВФоне Тогда
ДлительныеОперации.СообщитьПрогресс(1);
КонецЕсли;
ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем();
Для каждого ИмяПодсистемы Из ОписанияПодсистем.Порядок Цикл
ОписаниеПодсистемы = ОписанияПодсистем.ПоИменам.Получить(ИмяПодсистемы);
Если НЕ ЗначениеЗаполнено(ОписаниеПодсистемы.ОсновнойСерверныйМодуль) Тогда
Продолжить;
КонецЕсли;
Модуль = ОбщегоНазначения.ОбщийМодуль(ОписаниеПодсистемы.ОсновнойСерверныйМодуль);
Модуль.ПередОбновлениемИнформационнойБазы();
КонецЦикла;
ОбновлениеИнформационнойБазыПереопределяемый.ПередОбновлениемИнформационнойБазы();
// Проверка наличия прав для обновления информационной базы.
Если НЕ ЕстьПраваНаОбновлениеИнформационнойБазы() Тогда
Сообщение = НСтр("ru = 'Недостаточно прав для обновления версии программы.'");
ЗаписатьОшибку(Сообщение);
ВызватьИсключение Сообщение;
КонецЕсли;
Если РежимОбновленияДанных = "ПереходСДругойПрограммы" Тогда
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Изменилось имя конфигурации на ""%1"".
|Будет выполнен переход с другой программы.'"),
Метаданные.Имя);
ИначеЕсли РежимОбновленияДанных = "ОбновлениеВерсии" Тогда
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Изменился номер версии конфигурации: с ""%1"" на ""%2"".
|Будет выполнено обновление информационной базы.'"),
ВерсияДанных, ВерсияМетаданных);
Иначе
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Выполняется начальное заполнение данных до версии ""%1"".'"),
ВерсияМетаданных);
КонецЕсли;
ЗаписатьИнформацию(Сообщение);
// Установка блокировки информационной базы.
БлокировкаУстановленаРанее = ПараметрыОбновления.УстановленнаяБлокировкаИБ <> Неопределено
И ПараметрыОбновления.УстановленнаяБлокировкаИБ.Установлена;
Если БлокировкаУстановленаРанее Тогда
ИтерацииОбновления = ИтерацииОбновления();
БлокировкаИБ = ПараметрыОбновления.УстановленнаяБлокировкаИБ;
Иначе
БлокировкаИБ = Неопределено;
ИтерацииОбновления = ЗаблокироватьИБ(БлокировкаИБ, ПараметрыОбновления.ИсключениеПриНевозможностиБлокировкиИБ);
Если БлокировкаИБ.Ошибка <> Неопределено Тогда
Результат.Возврат = БлокировкаИБ.Ошибка;
Возврат Результат;
КонецЕсли;
КонецЕсли;
Результат.Вставить("РежимОбновленияДанных", РежимОбновленияДанных);
Результат.Вставить("ИтерацииОбновления", ИтерацииОбновления);
Результат.Вставить("БлокировкаИБ", БлокировкаИБ);
Результат.Вставить("БлокировкаУстановленаРанее", БлокировкаУстановленаРанее);
Результат.Вставить("ВерсияДанных", ВерсияДанных);
Результат.Вставить("ВерсияМетаданных", ВерсияМетаданных);
Возврат Результат;
КонецФункции
Процедура ВыполнитьДействияПриОбновленииИнформационнойБазы(ПараметрыОбновления, ДополнительныеПараметры)
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
// Установка привилегированного режима для возможности обновления ИБ в модели сервиса,
// в случае когда администратор области данных выполняет вход в область до завершения обновления области.
Если ОбщегоНазначения.РазделениеВключено() И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
УстановитьПривилегированныйРежим(Истина);
КонецЕсли;
КонецЕсли;
РежимОбновленияДанных = ДополнительныеПараметры.РежимОбновленияДанных;
ИтерацииОбновления = ДополнительныеПараметры.ИтерацииОбновления;
БлокировкаИБ = ДополнительныеПараметры.БлокировкаИБ;
БлокировкаУстановленаРанее = ДополнительныеПараметры.БлокировкаУстановленаРанее;
РежимВыполненияОтложенногоОбновления = ДополнительныеПараметры.РежимВыполненияОтложенногоОбновления;
ВыполнитьОтложенноеОбновлениеСейчас = ДополнительныеПараметры.ВыполнитьОтложенноеОбновлениеСейчас;
ОперативноеОбновление = БлокировкаИБ.ОперативноеОбновление;
Попытка
Если РежимОбновленияДанных = "ПереходСДругойПрограммы" Тогда
ПерейтиСДругойПрограммы(ИтерацииОбновления);
ИтерацииОбновления = ИтерацииОбновления();
РежимОбновленияДанных = РежимОбновленияДанных();
ОперативноеОбновление = Ложь;
КонецЕсли;
Исключение
Если Не БлокировкаУстановленаРанее Тогда
РазблокироватьИБ(БлокировкаИБ);
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
ОбновлениеИнформационнойБазыПереопределяемый.ПередФормированиеСпискаОтложенныхОбработчиков(ИтерацииОбновления);
Обработки.ОписаниеОбработчиковОбновления.ЗаполнитьНомерОчереди(ИтерацииОбновления);
ОбновитьСписокВыполняемыхОбработчиковОбновления(ИтерацииОбновления);
СброситьПрогрессВыполненияОбработчиков();
ОчиститьЗарегистрированныеПроблемыСДанными();
Если ПараметрыОбновления.ВФоне Тогда
ДлительныеОперации.СообщитьПрогресс(10);
КонецЕсли;
Параметры = Новый Структура;
Параметры.Вставить("ХодВыполненияОбработчиков", КоличествоОбработчиковНаТекущуюВерсию(ИтерацииОбновления, РежимВыполненияОтложенногоОбновления));
Параметры.Вставить("ОперативноеОбновление", ОперативноеОбновление);
Параметры.Вставить("ВФоне", ПараметрыОбновления.ВФоне);
Параметры.Вставить("ПриЗапускеКлиентскогоПриложения", ПараметрыОбновления.ПриЗапускеКлиентскогоПриложения);
Параметры.Вставить("РежимВыполненияОтложенногоОбновления", РежимВыполненияОтложенногоОбновления);
Сообщение = НСтр("ru = 'Для обновления программы на новую версию будут выполнены обработчики: %1'");
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Сообщение, Параметры.ХодВыполненияОбработчиков.ВсегоОбработчиков);
ЗаписатьИнформацию(Сообщение);
Попытка
// Выполняем все обработчики обновления для подсистем конфигурации.
Для Каждого ИтерацияОбновления Из ИтерацииОбновления Цикл
ИтерацияОбновления.ВыполненныеОбработчики = ВыполнитьИтерациюОбновления(ИтерацияОбновления, Параметры);
КонецЦикла;
// Очистка списка новых подсистем.
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
СведенияОбОбновлении.НовыеПодсистемы = Новый Массив;
СведенияОбОбновлении.ВсеНовыеПодсистемы = Новый Массив;
ЗаполнитьДанныеДляПараллельногоОтложенногоОбновления(Параметры);
ЗаписатьСведенияОбОбновленииИнформационнойБазы(СведенияОбОбновлении);
// Для файловой базы отложенные обработчики выполняются в основном цикле обновления.
Если ВыполнитьОтложенноеОбновлениеСейчас Тогда
ВыполнитьОтложенноеОбновлениеСейчас(Параметры);
КонецЕсли;
Исключение
Если Не БлокировкаУстановленаРанее Тогда
РазблокироватьИБ(БлокировкаИБ);
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
Процедура ВыполнитьДействияПослеОбновленияИнформационнойБазы(ПараметрыОбновления, ДополнительныеПараметры)
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
// Установка привилегированного режима для возможности обновления ИБ в модели сервиса,
// в случае когда администратор области данных выполняет вход в область до завершения обновления области.
Если ОбщегоНазначения.РазделениеВключено() И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
УстановитьПривилегированныйРежим(Истина);
КонецЕсли;
КонецЕсли;
РежимОбновленияДанных = ДополнительныеПараметры.РежимОбновленияДанных;
ИтерацииОбновления = ДополнительныеПараметры.ИтерацииОбновления;
БлокировкаИБ = ДополнительныеПараметры.БлокировкаИБ;
ОперативноеОбновление = ДополнительныеПараметры.БлокировкаИБ.ОперативноеОбновление;
ВерсияДанных = ДополнительныеПараметры.ВерсияДанных;
ВерсияМетаданных = ДополнительныеПараметры.ВерсияМетаданных;
БлокировкаУстановленаРанее = ДополнительныеПараметры.БлокировкаУстановленаРанее;
РежимВыполненияОтложенногоОбновления = ДополнительныеПараметры.РежимВыполненияОтложенногоОбновления;
ВыполнитьОтложенноеОбновлениеСейчас = ДополнительныеПараметры.ВыполнитьОтложенноеОбновлениеСейчас;
// Отключение монопольного режима.
Если Не БлокировкаУстановленаРанее Тогда
РазблокироватьИБ(БлокировкаИБ);
КонецЕсли;
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Обновление информационной базы на версию ""%1"" выполнено успешно.'"), ВерсияМетаданных);
ЗаписатьИнформацию(Сообщение);
ВыводитьОписаниеОбновлений = (РежимОбновленияДанных <> "НачальноеЗаполнение");
ОбновитьПовторноИспользуемыеЗначения();
// После обновления информационной базы.
//
ВыполнитьОбработчикиПослеОбновленияИнформационнойБазы(
ИтерацииОбновления,
Константы.ДетализироватьОбновлениеИБВЖурналеРегистрации.Получить(),
ВыводитьОписаниеОбновлений,
ОперативноеОбновление);
ОбновлениеИнформационнойБазыПереопределяемый.ПослеОбновленияИнформационнойБазы(
ВерсияДанных,
ВерсияМетаданных,
ИтерацииОбновления,
ВыводитьОписаниеОбновлений,
Не ОперативноеОбновление);
// Выгрузка сообщения обмена после перезапуска в связи с получением изменений конфигурации.
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда
МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер");
МодульОбменДаннымиСервер.ПослеОбновленияИнформационнойБазы();
КонецЕсли;
// Для клиент-серверной базы запланировать выполнение отложенных обработчиков обновления.
Если РежимВыполненияОтложенногоОбновления <> Неопределено
И РежимВыполненияОтложенногоОбновления = "Отложенно" Тогда
ЗапланироватьОтложенноеОбновление();
КонецЕсли;
ОпределитьВыводОписанияОбновлений(ВыводитьОписаниеОбновлений);
// Сброс неуспешного статуса обновления конфигурации при завершении обновления вручную (без скрипта).
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбновлениеКонфигурации") Тогда
МодульОбновлениеКонфигурации = ОбщегоНазначения.ОбщийМодуль("ОбновлениеКонфигурации");
МодульОбновлениеКонфигурации.ПослеОбновленияИнформационнойБазы();
КонецЕсли;
ОбновитьПовторноИспользуемыеЗначения();
УстановитьПривилегированныйРежим(Истина);
ПараметрЗапускаКлиента = ПараметрыСеанса.ПараметрыКлиентаНаСервере.Получить("ПараметрЗапуска");
Если СтрНайти(НРег(ПараметрЗапускаКлиента), НРег("ЗапуститьОбновлениеИнформационнойБазы")) > 0 Тогда
СтандартныеПодсистемыСервер.ЗарегистрироватьИзменениеПриоритетныхДанныхДляПодчиненныхУзловРИБ();
КонецЕсли;
УстановитьПривилегированныйРежим(Ложь);
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
МодульУправлениеДоступомСлужебный = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступомСлужебный");
МодульУправлениеДоступомСлужебный.ОбновитьДоступПослеОбновленияИнформационнойБазы(
ВыполнитьОтложенноеОбновлениеСейчас);
КонецЕсли;
Если Не ПараметрыОбновления.ПриЗапускеКлиентскогоПриложения Тогда
УстановитьЗапускОбновленияИнформационнойБазы(Ложь);
ПараметрыСеанса.ВыполняетсяОбновлениеИБ = Ложь;
КонецЕсли;
КонецПроцедуры
// Возвращает признак разрешения использования многопоточного обновления.
// Многопоточное обновление можно включить в ОбновлениеИнформационнойБазыПереопределяемый.ПриОпределенииНастроек().
//
// Возвращаемое значение:
// Булево - если Истина, многопоточное обновление разрешено. По умолчанию - Ложь (для обратной совместимости).
//
Функция РазрешеноМногопоточноеОбновление() Экспорт
Параметры = НастройкиПодсистемы();
Возврат Параметры.МногопоточноеОбновление;
КонецФункции
// Параметры:
// ИмяПараметра - Строка
// УстановленныеПараметры - Массив из Строка
//
Процедура УстановкаПараметровСеанса(Знач ИмяПараметра, УстановленныеПараметры) Экспорт
Если ИмяПараметра = "ВыполняетсяОбновлениеИБ" Тогда
ПараметрыСеанса.ВыполняетсяОбновлениеИБ = ОбновлениеИнформационнойБазы.НеобходимоОбновлениеИнформационнойБазы();
УстановленныеПараметры.Добавить("ВыполняетсяОбновлениеИБ");
ИначеЕсли ИмяПараметра = "ПараметрыОбработчикаОбновления" Тогда
ПараметрыСеанса.ПараметрыОбработчикаОбновления = Новый ФиксированнаяСтруктура(НовыеПараметрыОбработчикаОбновления());
УстановленныеПараметры.Добавить("ПараметрыОбработчикаОбновления");
КонецЕсли;
КонецПроцедуры
// Возвращает числовой вес версии для сравнения версий между собой.
//
// Параметры:
// Версия - Строка - версия в строковом формате.
//
// Возвращаемое значение:
// Число - вес версии
//
Функция ВесВерсии(Знач Версия) Экспорт
Если Версия = "" Тогда
Возврат 0;
КонецЕсли;
Если СтрНачинаетсяС(Версия, "ОтладкаОбработчика") Тогда
Возврат 99000000000;
КонецЕсли;
Возврат ВесВерсииИзМассиваСтрок(СтрРазделить(Версия, "."));
КонецФункции
// Для внутреннего использования.
//
// Параметры:
// ИмяКонфигурацииИлиБиблиотеки - Строка
// Версия - Строка
// Обработчики - см. ОбновлениеИнформационнойБазы.НоваяТаблицаОбработчиковОбновления
// ЭтоОсновнаяКонфигурация - Булево
// - Неопределено
// Возвращаемое значение:
// Структура:
// * ПредыдущаяВерсия - Строка
// * ОсновнойСерверныйМодуль - Строка
// * ИмяОсновногоСерверногоМодуля - Строка
// * ВыполненныеОбработчики - Неопределено
// * Обработчики - ТаблицаЗначений:
// ** НачальноеЗаполнение - Булево
// ** Версия - Строка
// ** Процедура - Строка
// ** РежимВыполнения - Строка
// ** ОбщиеДанные - Булево
// ** УправлениеОбработчиками - Булево
// ** Комментарий - Строка
// ** Идентификатор - УникальныйИдентификатор
// ** БлокируемыеОбъекты - Строка
// ** ПроцедураПроверки - Строка
// ** ПроцедураЗаполненияДанныхОбновления - Строка
// ** ЗапускатьТолькоВГлавномУзле - Булево
// ** ЗапускатьИВПодчиненномУзлеРИБСФильтрами - Булево
// ** ЧитаемыеОбъекты - Строка
// ** ИзменяемыеОбъекты - Строка
// ** ПриоритетыВыполнения - ТаблицаЗначений
// ** ВыполнятьВГруппеОбязательных - Булево
// ** Приоритет - Число
// ** МонопольныйРежим - Неопределено
// - Булево
// * ЭтоОсновнаяКонфигурация - Булево
// - Неопределено
//
Функция ИтерацияОбновления(ИмяКонфигурацииИлиБиблиотеки, Версия, Обработчики, ЭтоОсновнаяКонфигурация = Неопределено) Экспорт
ИтерацияОбновления = Новый Структура;
ИтерацияОбновления.Вставить("Подсистема", ИмяКонфигурацииИлиБиблиотеки);
ИтерацияОбновления.Вставить("Версия", Версия);
ИтерацияОбновления.Вставить("ЭтоОсновнаяКонфигурация",
?(ЭтоОсновнаяКонфигурация <> Неопределено, ЭтоОсновнаяКонфигурация, ИмяКонфигурацииИлиБиблиотеки = Метаданные.Имя));
ИтерацияОбновления.Вставить("Обработчики", Обработчики);
ИтерацияОбновления.Вставить("ВыполненныеОбработчики", Неопределено);
ИтерацияОбновления.Вставить("ИмяОсновногоСерверногоМодуля", "");
ИтерацияОбновления.Вставить("ОсновнойСерверныйМодуль", "");
ИтерацияОбновления.Вставить("ПредыдущаяВерсия", "");
Возврат ИтерацияОбновления;
КонецФункции
// Проверить права текущего пользователя на выполнение обновления информационной базы.
Функция ЕстьПраваНаОбновлениеИнформационнойБазы(УчитыватьПривилегированныйРежим = Истина, РазделенныеДанные = Неопределено) Экспорт
ПроверятьПраваАдминистрированияСистемы = Истина;
Если РазделенныеДанные = Неопределено Тогда
РазделенныеДанные = НЕ ОбщегоНазначения.РазделениеВключено()
ИЛИ ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных();
КонецЕсли;
Если ОбщегоНазначения.РазделениеВключено()
И РазделенныеДанные Тогда
Если НЕ ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Возврат Ложь;
КонецЕсли;
ПроверятьПраваАдминистрированияСистемы = Ложь;
КонецЕсли;
Возврат Пользователи.ЭтоПолноправныйПользователь(
, ПроверятьПраваАдминистрированияСистемы, УчитыватьПривилегированныйРежим);
КонецФункции
// Для внутреннего использования.
//
Функция ОбновитьИнформационнуюБазуВФоне(УникальныйИдентификаторФормы, БлокировкаИБ) Экспорт
// Запуск фонового задания
ПараметрыОбновленияИБ = Новый Структура;
ПараметрыОбновленияИБ.Вставить("ИсключениеПриНевозможностиБлокировкиИБ", Ложь);
ПараметрыОбновленияИБ.Вставить("БлокировкаИБ", БлокировкаИБ);
ПараметрыОбновленияИБ.Вставить("ПараметрыКлиентаНаСервере", ПараметрыСеанса.ПараметрыКлиентаНаСервере);
// Установка монопольного режима до запуска фонового выполнения обновления.
Попытка
ЗаблокироватьИБ(ПараметрыОбновленияИБ.БлокировкаИБ, Ложь);
Исключение
ИнформацияОбОшибке = ИнформацияОбОшибке();
Результат = Новый Структура;
Результат.Вставить("Статус", "Ошибка");
Результат.Вставить("БлокировкаИБ", ПараметрыОбновленияИБ.БлокировкаИБ);
Результат.Вставить("КраткоеПредставлениеОшибки", КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
Результат.Вставить("ПодробноеПредставлениеОшибки", ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));
Возврат Результат;
КонецПопытки;
ПараметрыОбновленияИБ.Вставить("ВФоне", Не ПараметрыОбновленияИБ.БлокировкаИБ.РежимОтладки);
Если Не ПараметрыОбновленияИБ.ВФоне Тогда
ПараметрыОбновленияИБ.Удалить("ПараметрыКлиентаНаСервере");
КонецЕсли;
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификаторФормы);
ПараметрыВыполнения.ОжидатьЗавершение = 0;
ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'Фоновое обновление информационной базы'");
Результат = ДлительныеОперации.ВыполнитьВФоне("ОбновлениеИнформационнойБазыСлужебный.ВыполнитьОбновлениеИнформационнойБазыВФоне",
ПараметрыОбновленияИБ, ПараметрыВыполнения);
Результат.Вставить("БлокировкаИБ", ПараметрыОбновленияИБ.БлокировкаИБ);
// Если обновление ИБ уже выполнилось - разблокируем ИБ.
Если Результат.Статус <> "Выполняется" Тогда
РазблокироватьИБ(ПараметрыОбновленияИБ.БлокировкаИБ);
КонецЕсли;
Возврат Результат;
КонецФункции
// Запускает обновление информационной базы в длительной операции.
Процедура ВыполнитьОбновлениеИнформационнойБазыВФоне(ПараметрыОбновленияИБ, АдресХранилища) Экспорт
Если ПараметрыОбновленияИБ.ВФоне Тогда
ПараметрыСеанса.ПараметрыКлиентаНаСервере = ПараметрыОбновленияИБ.ПараметрыКлиентаНаСервере;
КонецЕсли;
ИнформацияОбОшибке = Неопределено;
Попытка
ПараметрыОбновления = ПараметрыОбновления();
ПараметрыОбновления.ИсключениеПриНевозможностиБлокировкиИБ = ПараметрыОбновленияИБ.ИсключениеПриНевозможностиБлокировкиИБ;
ПараметрыОбновления.ПриЗапускеКлиентскогоПриложения = Истина;
ПараметрыОбновления.Перезапустить = Ложь;
ПараметрыОбновления.УстановленнаяБлокировкаИБ = ПараметрыОбновленияИБ.БлокировкаИБ;
ПараметрыОбновления.ВФоне = ПараметрыОбновленияИБ.ВФоне;
Результат = ВыполнитьОбновлениеИнформационнойБазы(ПараметрыОбновления);
Исключение
ИнформацияОбОшибке = ИнформацияОбОшибке();
// Переход в режим открытия формы повторной синхронизации данных перед запуском
// с двумя вариантами "Синхронизировать и продолжить" и "Продолжить".
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными")
И ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ() Тогда
МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер");
МодульОбменДаннымиСервер.ВключитьПовторениеЗагрузкиСообщенияОбменаДаннымиПередЗапуском();
КонецЕсли;
КонецПопытки;
Если ИнформацияОбОшибке <> Неопределено Тогда
РезультатОбновления = Новый Структура;
РезультатОбновления.Вставить("КраткоеПредставлениеОшибки", КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
РезультатОбновления.Вставить("ПодробноеПредставлениеОшибки", ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));
ИначеЕсли Не ПараметрыОбновленияИБ.ВФоне Тогда
РезультатОбновления = Результат;
Иначе
РезультатОбновления = Новый Структура;
РезультатОбновления.Вставить("ПараметрыКлиентаНаСервере", ПараметрыСеанса.ПараметрыКлиентаНаСервере);
РезультатОбновления.Вставить("Результат", Результат);
КонецЕсли;
ПоместитьВоВременноеХранилище(РезультатОбновления, АдресХранилища);
КонецПроцедуры
Функция ОбновлениеПодОграниченнымиПравами() Экспорт
Если Не ОбщегоНазначения.РазделениеВключено()
Или Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Возврат Ложь;
КонецЕсли;
Результат = "";
// АПК:280 -выкл ошибки пишутся в журнал регистрации, пользователю не показываются.
Попытка
УстановитьПривилегированныйРежим(Истина);
ОтметкаНачалаОбновления = ОтметкаНачалаОбновления();
Если ОтметкаНачалаОбновления.МожноВыполнятьОбновление Тогда
Результат = ОбновлениеИнформационнойБазы.ВыполнитьОбновлениеИнформационнойБазы();
КонецЕсли;
УстановитьПривилегированныйРежим(Ложь);
Исключение
// Обработка исключения не требуется.
КонецПопытки;
// АПК:280 -вкл.
Возврат (Результат = "Успешно" Или Результат = "НеТребуется");
КонецФункции
// Для внутреннего использования.
//
Функция ЗаблокироватьИБ(БлокировкаИБ, ИсключениеПриНевозможностиБлокировкиИБ)
ИтерацииОбновления = Неопределено;
Если БлокировкаИБ = Неопределено Тогда
БлокировкаИБ = БлокировкаИБ();
КонецЕсли;
БлокировкаИБ.Установлена = Истина;
Если ОбщегоНазначения.РазделениеВключено() Тогда
БлокировкаИБ.РежимОтладки = Ложь;
Иначе
БлокировкаИБ.РежимОтладки = ОбщегоНазначения.РежимОтладки();
КонецЕсли;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
БлокировкаИБ.КлючЗаписи = МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.ЗаблокироватьВерсииОбластиДанных();
КонецЕсли;
ИтерацииОбновления = ИтерацииОбновления();
БлокировкаИБ.ОперативноеОбновление = Ложь;
Если БлокировкаИБ.РежимОтладки Тогда
Возврат ИтерацииОбновления;
КонецЕсли;
// Установка монопольного режима для обновления информационной базы.
ИнформацияОбОшибке = Неопределено;
Попытка
Если НЕ МонопольныйРежим() Тогда
УстановитьМонопольныйРежим(Истина);
КонецЕсли;
Возврат ИтерацииОбновления;
Исключение
Если ВозможноОперативноеОбновление(ИтерацииОбновления) Тогда
БлокировкаИБ.ОперативноеОбновление = Истина;
Возврат ИтерацииОбновления;
КонецЕсли;
ИнформацияОбОшибке = ИнформацияОбОшибке();
КонецПопытки;
// Обработка неудачной попытки установки монопольного режима.
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Невозможно выполнить обновление информационной базы:
|- Невозможно установить монопольный режим
|- Версия конфигурации не предусматривает обновление без установки монопольного режима
|
|Подробности ошибки:
|%1'"),
КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
ЗаписатьОшибку(Сообщение);
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.РазблокироватьВерсииОбластиДанных(БлокировкаИБ.КлючЗаписи);
КонецЕсли;
Если Не ИсключениеПриНевозможностиБлокировкиИБ
И ОбщегоНазначения.ИнформационнаяБазаФайловая()
И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЗавершениеРаботыПользователей") Тогда
ПараметрЗапускаКлиента = ПараметрыСеанса.ПараметрыКлиентаНаСервере.Получить("ПараметрЗапуска");
Если СтрНайти(ПараметрЗапускаКлиента, "РегламентныеЗаданияОтключены") = 0 Тогда
БлокировкаИБ.Ошибка = "ЗаблокироватьВыполнениеРегламентныхЗаданий";
Иначе
БлокировкаИБ.Ошибка = "ОшибкаУстановкиМонопольногоРежима";
КонецЕсли;
КонецЕсли;
ВызватьИсключение Сообщение;
КонецФункции
// Для внутреннего использования.
//
Процедура РазблокироватьИБ(БлокировкаИБ) Экспорт
Если БлокировкаИБ.РежимОтладки Тогда
Возврат;
КонецЕсли;
Если МонопольныйРежим() Тогда
Пока ТранзакцияАктивна() Цикл
ОтменитьТранзакцию();
КонецЦикла;
УстановитьМонопольныйРежим(Ложь);
КонецЕсли;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.РазблокироватьВерсииОбластиДанных(БлокировкаИБ.КлючЗаписи);
КонецЕсли;
КонецПроцедуры
// Для внутреннего использования.
//
Функция БлокировкаИБ()
Результат = Новый Структура;
Результат.Вставить("Установлена", Ложь);
Результат.Вставить("Ошибка", Неопределено);
Результат.Вставить("ОперативноеОбновление", Неопределено);
Результат.Вставить("КлючЗаписи", Неопределено);
Результат.Вставить("РежимОтладки", Неопределено);
Возврат Результат;
КонецФункции
// Для внутреннего использования.
//
Функция ПараметрыОбновления() Экспорт
Результат = Новый Структура;
Результат.Вставить("ИсключениеПриНевозможностиБлокировкиИБ", Истина);
Результат.Вставить("ПриЗапускеКлиентскогоПриложения", Ложь);
Результат.Вставить("Перезапустить", Ложь);
Результат.Вставить("УстановленнаяБлокировкаИБ", Неопределено);
Результат.Вставить("ВФоне", Ложь);
Результат.Вставить("ВыполнятьОтложенныеОбработчики", Ложь);
Возврат Результат;
КонецФункции
// Для внутреннего использования.
//
Функция НоваяТаблицаОбработчиковПереходаСДругойПрограммы()
Обработчики = Новый ТаблицаЗначений;
Обработчики.Колонки.Добавить("ПредыдущееИмяКонфигурации", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(0)));
Обработчики.Колонки.Добавить("Процедура", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(0)));
Обработчики.Колонки.Добавить("ОбщиеДанные", Новый ОписаниеТипов("Булево"));
Возврат Обработчики;
КонецФункции
// Для внутреннего использования.
//
Функция ОбработчикиПереходаСДругойПрограммы(ПредыдущееИмяКонфигурации, ИтерацииОбновления)
ОбработчикиПерехода = НоваяТаблицаОбработчиковПереходаСДругойПрограммы();
ИмяОсновнойКонфигурации = Метаданные.Имя;
// Начальное заполнение для объектов новых подсистем.
ОбработчикиПерехода = НоваяТаблицаОбработчиковПереходаСДругойПрограммы();
ИмяОсновнойКонфигурации = Метаданные.Имя;
ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем();
ПодсистемыКонфигурации = ОписанияПодсистем.ПоИменам;
ВсеНовыеПодсистемы = СведенияОбОбновленииИнформационнойБазы().ВсеНовыеПодсистемы;
// Добавление обработчика заполнения предопределенных данных.
ОбработчикПерехода = ОбработчикиПерехода.Добавить();
ОбработчикПерехода.ПредыдущееИмяКонфигурации = "*";
ОбработчикПерехода.ОбщиеДанные = Ложь;
ОбработчикПерехода.Процедура = ОбработчикНачальногоЗаполненияПредопределенных();
НовыеОбъектыМетаданных = Новый Массив;
Для Каждого Подсистема Из ВсеНовыеПодсистемы Цикл
ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(Подсистема);
Если ОбъектМетаданных = Неопределено Тогда
Продолжить;
КонецЕсли;
Если ОбъектМетаданных.ВключатьВКомандныйИнтерфейс Тогда
Продолжить;
КонецЕсли;
Для Каждого ОбъектПодсистемы Из ОбъектМетаданных.Состав Цикл
НовыеОбъектыМетаданных.Добавить(ОбъектПодсистемы.ПолноеИмя());
КонецЦикла;
КонецЦикла;
Для Каждого ИтерацияОбновления Из ИтерацииОбновления Цикл
ОписаниеПодсистемы = ПодсистемыКонфигурации.Получить(ИтерацияОбновления.Подсистема);
Если Не ОписаниеПодсистемы.ЗаполнятьДанныеНовыхПодсистемПриПереходеСДругойПрограммы Тогда
Продолжить;
КонецЕсли;
Отбор = Новый Структура;
Отбор.Вставить("НачальноеЗаполнение", Истина);
ОбработчикиНачальногоЗаполнения = ИтерацияОбновления.Обработчики.НайтиСтроки(Отбор);
Для Каждого Обработчик Из ОбработчикиНачальногоЗаполнения Цикл
Если Обработчик.РежимВыполнения = "Отложенно"
Или Обработчик.НеВыполнятьПриПереходеСДругойПрограммы Тогда
Продолжить;
КонецЕсли;
Позиция = СтрНайти(Обработчик.Процедура, ".", НаправлениеПоиска.СКонца);
ИмяМенеджера = Лев(Обработчик.Процедура, Позиция - 1);
ПолноеИмяОбъекта = ИмяОбъектаМетаданныхПоИмениМенеджера(ИмяМенеджера);
Если НовыеОбъектыМетаданных.Найти(ПолноеИмяОбъекта) <> Неопределено Тогда
ОбработчикПерехода = ОбработчикиПерехода.Добавить();
ОбработчикПерехода.ПредыдущееИмяКонфигурации = "*";
ОбработчикПерехода.ОбщиеДанные = Обработчик.ОбщиеДанные;
ОбработчикПерехода.Процедура = Обработчик.Процедура;
КонецЕсли;
КонецЦикла;
КонецЦикла;
// Добавление штатных обработчиков перехода.
ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем();
Для каждого ИмяПодсистемы Из ОписанияПодсистем.Порядок Цикл
ОписаниеПодсистемы = ОписанияПодсистем.ПоИменам.Получить(ИмяПодсистемы); // см. СтандартныеПодсистемыПовтИсп.НовоеОписаниеПодсистемы
Если НЕ ЗначениеЗаполнено(ОписаниеПодсистемы.ОсновнойСерверныйМодуль) Тогда
Продолжить;
КонецЕсли;
Если ОписаниеПодсистемы.Имя <> ИмяОсновнойКонфигурации Тогда
Продолжить;
КонецЕсли;
Модуль = ОбщегоНазначения.ОбщийМодуль(ОписаниеПодсистемы.ОсновнойСерверныйМодуль);
Модуль.ПриДобавленииОбработчиковПереходаСДругойПрограммы(ОбработчикиПерехода);
КонецЦикла;
// Дополнительно добавляются обязательные обработчики перехода БСП.
ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковПереходаСДругойПрограммы(ОбработчикиПерехода);
Отбор = Новый Структура("ПредыдущееИмяКонфигурации", "*");
Если ОбщегоНазначения.РазделениеВключено() Тогда
Отбор.Вставить("ОбщиеДанные", Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных());
КонецЕсли;
ВыбранныеОбработчики = ОбработчикиПерехода.НайтиСтроки(Отбор);
Отбор.ПредыдущееИмяКонфигурации = ПредыдущееИмяКонфигурации;
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ВыбранныеОбработчики, ОбработчикиПерехода.НайтиСтроки(Отбор), Истина);
Результат = Новый Структура;
Результат.Вставить("Обработчики", ВыбранныеОбработчики);
Результат.Вставить("НовыеОбъекты", НовыеОбъектыМетаданных);
Возврат Результат;
КонецФункции
Процедура ПерейтиСДругойПрограммы(ИтерацииОбновления)
ЭтоНеразделенныйСеанс = Не ОбщегоНазначения.РазделениеВключено()
Или Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных();
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = Неопределено;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
КонецЕсли;
// Предыдущее имя конфигурации, с которой нужно выполнить переход.
Если ЭтоНеразделенныйСеанс Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ВерсииПодсистем.ИмяПодсистемы КАК ИмяПодсистемы,
| ВерсииПодсистем.Версия КАК Версия
|ИЗ
| РегистрСведений.ВерсииПодсистем КАК ВерсииПодсистем
|ГДЕ
| ВерсииПодсистем.ЭтоОсновнаяКонфигурация = ИСТИНА";
РезультатЗапроса = Запрос.Выполнить();
ИначеЕсли МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = Неопределено Тогда
// Отсутствует подсистема ОбновлениеВерсииИБВМоделиСервиса.
Возврат;
Иначе
РезультатЗапроса = МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.ОсновнаяКонфигурацияВОбластиДанных();
КонецЕсли;
// Если по каким-то причинам не отработал обработчик обновления ЗаполнитьРеквизитЭтоОсновнаяКонфигурация.
Если РезультатЗапроса.Пустой() Тогда
Возврат;
КонецЕсли;
РезультатЗапроса = РезультатЗапроса.Выгрузить()[0];
ПредыдущееИмяКонфигурации = РезультатЗапроса.ИмяПодсистемы;
ПредыдущаяВерсияКонфигурации = РезультатЗапроса.Версия;
// Проверка заполнения реквизита ЭтоОсновнаяКонфигурация в областях.
Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.ЗаполнитьПризнакЭтоОсновнаяКонфигурация(ПредыдущееИмяКонфигурации);
Иначе
ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем();
ОписаниеПредыдущейПодсистемы = ОписанияПодсистем.ПоИменам.Получить(ПредыдущееИмяКонфигурации);
Если ОписаниеПредыдущейПодсистемы = Неопределено Тогда
// Предыдущая подсистема была удалена.
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ИмяБиблиотеки", ПредыдущееИмяКонфигурации);
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыОбработчиковОбновления.Выполнен);
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.ИмяОбработчика КАК ИмяОбработчика
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.ИмяБиблиотеки = &ИмяБиблиотеки
| И ОбработчикиОбновления.Статус <> &Статус";
Результат = Запрос.Выполнить().Выгрузить();
Для Каждого Строка Из Результат Цикл
НаборЗаписей = РегистрыСведений.ОбработчикиОбновления.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ИмяОбработчика.Установить(Строка.ИмяОбработчика);
НаборЗаписей.Прочитать();
НаборЗаписей[0].ИмяБиблиотеки = Метаданные.Имя;
НаборЗаписей.Записать();
КонецЦикла;
КонецЕсли;
КонецЕсли;
ОбработчикиИНовыеОбъекты = ОбработчикиПереходаСДругойПрограммы(ПредыдущееИмяКонфигурации, ИтерацииОбновления);
Обработчики = ОбработчикиИНовыеОбъекты.Обработчики;
НовыеОбъекты = ОбработчикиИНовыеОбъекты.НовыеОбъекты;
ПодсистемаСуществует = ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом");
// Выполняем все обработчики перехода.
Для Каждого Обработчик Из Обработчики Цикл
ТранзакцияАктивнаНаНачалоВыполнения = ТранзакцияАктивна();
ОтключитьОбновлениеКлючейДоступа(Истина, ПодсистемаСуществует);
Попытка
// Начальное заполнение предопределенных для новых объектов.
Если Обработчик.Процедура = ОбработчикНачальногоЗаполненияПредопределенных() Тогда
ПараметрыОбработчика = Новый Массив;
ПараметрыОбработчика.Добавить(Ложь);
ПараметрыОбработчика.Добавить(Новый Структура("НовыеОбъекты", НовыеОбъекты));
ОбщегоНазначения.ВыполнитьМетодКонфигурации(Обработчик.Процедура, ПараметрыОбработчика);
Иначе
// Выполнение обработчиков перехода.
ОбщегоНазначения.ВыполнитьМетодКонфигурации(Обработчик.Процедура);
КонецЕсли;
ОтключитьОбновлениеКлючейДоступа(Ложь, ПодсистемаСуществует);
Исключение
ОтключитьОбновлениеКлючейДоступа(Ложь, ПодсистемаСуществует);
ИмяОбработчика = Обработчик.Процедура;
ЗаписатьОшибку(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'При вызове обработчика перехода с другой программы
|""%1""
|произошла ошибка:
|""%2"".'"),
ИмяОбработчика,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
ВызватьИсключение;
КонецПопытки;
ПроверитьВложеннуюТранзакцию(ТранзакцияАктивнаНаНачалоВыполнения, Обработчик.Процедура);
КонецЦикла;
Параметры = Новый Структура();
Параметры.Вставить("ВыполнитьОбновлениеСВерсии", Истина);
Параметры.Вставить("ВерсияКонфигурации", Метаданные.Версия);
Параметры.Вставить("ОчиститьСведенияОПредыдущейКонфигурации", Истина);
ПриЗавершенииПереходаСДругойПрограммы(ПредыдущееИмяКонфигурации, ПредыдущаяВерсияКонфигурации, Параметры);
// Установка текущих имени и версии конфигурации.
НачатьТранзакцию();
Попытка
Если Параметры.ОчиститьСведенияОПредыдущейКонфигурации Тогда
Если ЭтоНеразделенныйСеанс Тогда
НаборЗаписей = РегистрыСведений.ВерсииПодсистем.СоздатьНаборЗаписей();
Иначе
НаборЗаписей = МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.ЗаписьВерсийПодсистемОбластейДанных();
КонецЕсли;
НаборЗаписей.Отбор.ИмяПодсистемы.Установить(ПредыдущееИмяКонфигурации);
НаборЗаписей.Записать();
КонецЕсли;
Если ЭтоНеразделенныйСеанс Тогда
НаборЗаписей = РегистрыСведений.ВерсииПодсистем.СоздатьНаборЗаписей();
Иначе
НаборЗаписей = МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.ЗаписьВерсийПодсистемОбластейДанных();
КонецЕсли;
НаборЗаписей.Отбор.ИмяПодсистемы.Установить(Метаданные.Имя);
ВерсияКонфигурации = Метаданные.Версия;
Если Параметры.ВыполнитьОбновлениеСВерсии Тогда
ВерсияКонфигурации = Параметры.ВерсияКонфигурации;
КонецЕсли;
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.ИмяПодсистемы = Метаданные.Имя;
НоваяЗапись.Версия = ВерсияКонфигурации;
Если ЭтоНеразделенныйСеанс Тогда
НоваяЗапись.ПланОбновления = Неопределено;
КонецЕсли;
НоваяЗапись.ЭтоОсновнаяКонфигурация = Истина;
НаборЗаписей.Записать();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
ОбновитьПовторноИспользуемыеЗначения();
КонецПроцедуры
Функция ОбработчикНачальногоЗаполненияПредопределенных()
Возврат "ОбновлениеИнформационнойБазыСлужебный.НачальноеЗаполнениеПредопределенныхДанных";
КонецФункции
Процедура ПриЗавершенииПереходаСДругойПрограммы(ПредыдущееИмяКонфигурации, ПредыдущаяВерсияКонфигурации, Параметры)
ИмяКонфигурации = Метаданные.Имя;
ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем();
Для каждого ИмяПодсистемы Из ОписанияПодсистем.Порядок Цикл
ОписаниеПодсистемы = ОписанияПодсистем.ПоИменам.Получить(ИмяПодсистемы); // см. СтандартныеПодсистемыПовтИсп.НовоеОписаниеПодсистемы
Если НЕ ЗначениеЗаполнено(ОписаниеПодсистемы.ОсновнойСерверныйМодуль) Тогда
Продолжить;
КонецЕсли;
Если ОписаниеПодсистемы.Имя <> ИмяКонфигурации Тогда
Продолжить;
КонецЕсли;
Модуль = ОбщегоНазначения.ОбщийМодуль(ОписаниеПодсистемы.ОсновнойСерверныйМодуль);
Модуль.ПриЗавершенииПереходаСДругойПрограммы(ПредыдущееИмяКонфигурации, ПредыдущаяВерсияКонфигурации, Параметры);
КонецЦикла;
КонецПроцедуры
Процедура ОбновлениеВерсииИБПередУдалениемСсылочногоОбъекта(Источник, Отказ) Экспорт
// АПК:75-выкл проверка ОбменДанными.Загрузка не требуется, т.к. данное событие
// должно выполняться всегда в процессе выполнения отложенного обновления.
Если ПолучитьФункциональнуюОпцию("ОтложенноеОбновлениеЗавершеноУспешно")
Или Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Возврат;
КонецЕсли;
Если Метаданные.ПланыОбмена.ОбновлениеИнформационнойБазы.Состав.Найти(Источник.Метаданные()) = Неопределено Тогда
Возврат;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОбновлениеИнформационнойБазы.Ссылка КАК Ссылка
|ИЗ
| ПланОбмена.ОбновлениеИнформационнойБазы КАК ОбновлениеИнформационнойБазы
|ГДЕ
| ОбновлениеИнформационнойБазы.ЭтотУзел = ЛОЖЬ";
УстановитьПривилегированныйРежим(Истина);
Узлы = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
ПланыОбмена.УдалитьРегистрациюИзменений(Узлы, Источник);
КонецПроцедуры
Процедура УпорядочитьВерсииОбработчиков(ОбработчикиПоВерсиям)
ОбработчикиПоВерсиям.Колонки.Добавить("ВерсияПорядок", Новый ОписаниеТипов("Число"));
Для Каждого СтрокаВерсия Из ОбработчикиПоВерсиям.Строки Цикл
Версия = СтрокаВерсия.Версия;
Если Версия = "*" Или Не ЗначениеЗаполнено(Версия) Тогда
СтрокаВерсия.ВерсияПорядок = 0;
ИначеЕсли СтрНачинаетсяС(Версия, "ОтладкаОбработчика") Тогда
СтрокаВерсия.ВерсияПорядок = 99000000000;
Иначе
СтрокаВерсия.ВерсияПорядок = ВесВерсииИзМассиваСтрок(СтрРазделить(Версия, "."));
КонецЕсли;
КонецЦикла;
ОбработчикиПоВерсиям.Строки.Сортировать("ВерсияПорядок Возр");
КонецПроцедуры
Процедура ДобавитьОбработчики(ИмяБиблиотеки, ОбработчикиПоВерсиям, ДобавленныеОбработчики)
Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
НаборРазделенныхОбработчиков = РегистрыСведений.ОбработчикиОбновления.СоздатьНаборЗаписей();
НаборРазделенныхОбработчиков.Прочитать();
КонецЕсли;
Если Не ОбщегоНазначения.РазделениеВключено() Или Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
НаборНеразделенныхОбработчиков = РегистрыСведений.ОбработчикиОбновленияОбщихДанных.СоздатьНаборЗаписей();
НаборНеразделенныхОбработчиков.Прочитать();
КонецЕсли;
Для Каждого Версия Из ОбработчикиПоВерсиям Цикл
Для Каждого Обработчик Из Версия.Строки Цикл
Если ДобавленныеОбработчики.Найти(Обработчик.ИмяОбработчика) <> Неопределено Тогда
Продолжить;
КонецЕсли;
Если Обработчик.ОбщиеДанные = Истина Тогда
Запись = НаборНеразделенныхОбработчиков.Добавить();
Иначе
Запись = НаборРазделенныхОбработчиков.Добавить();
КонецЕсли;
ЗаполнитьЗначенияСвойств(Запись, Обработчик, , "РежимВыполнения");
Если Не ЗначениеЗаполнено(Обработчик.РежимВыполнения)
И (Обработчик.МонопольныйРежим = Истина Или Обработчик.МонопольныйРежим = Неопределено) Тогда
РежимВыполнения = Перечисления.РежимыВыполненияОбработчиков.Монопольно;
ИначеЕсли Не ЗначениеЗаполнено(Обработчик.РежимВыполнения) И Обработчик.МонопольныйРежим = Ложь Тогда
РежимВыполнения = Перечисления.РежимыВыполненияОбработчиков.Оперативно;
Иначе
РежимВыполнения = Перечисления.РежимыВыполненияОбработчиков[Обработчик.РежимВыполнения];
КонецЕсли;
Запись.РежимВыполнения = РежимВыполнения;
Запись.Статус = Перечисления.СтатусыОбработчиковОбновления.НеВыполнялся;
Запись.ИмяБиблиотеки = ИмяБиблиотеки;
ДобавленныеОбработчики.Добавить(Обработчик.ИмяОбработчика);
КонецЦикла;
КонецЦикла;
// АПК:1327-выкл нет конкурентной работы с регистром
Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
НаборРазделенныхОбработчиков.Записать();
КонецЕсли;
Если Не ОбщегоНазначения.РазделениеВключено() Или Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
НаборНеразделенныхОбработчиков.Записать();
КонецЕсли;
// АПК:1327-вкл
КонецПроцедуры
Процедура УстановитьСтатусОбработчика(ИмяОбработчика, Статус, ТекстОшибки = "")
НаборЗаписей = Неопределено;
Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
НаборЗаписей = РегистрыСведений.ОбработчикиОбновления.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ИмяОбработчика.Установить(ИмяОбработчика);
НаборЗаписей.Прочитать();
КонецЕсли;
ДоступноЧтениеНеразделенныхДанных = Не ОбщегоНазначения.РазделениеВключено()
Или Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных();
Если ДоступноЧтениеНеразделенныхДанных И (НаборЗаписей = Неопределено Или НаборЗаписей.Количество() = 0) Тогда
НаборЗаписей = РегистрыСведений.ОбработчикиОбновленияОбщихДанных.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ИмяОбработчика.Установить(ИмяОбработчика);
НаборЗаписей.Прочитать();
КонецЕсли;
Если НаборЗаписей.Количество() = 0 Тогда
Возврат;
КонецЕсли;
Запись = НаборЗаписей[0];
Запись.Статус = Перечисления.СтатусыОбработчиковОбновления[Статус];
Запись.ИнформацияОбОшибке = ТекстОшибки;
НаборЗаписей.Записать();
КонецПроцедуры
Процедура УстановитьСвойствоОбработчика(ИмяОбработчика, Свойство, Значение) Экспорт
Свойства = Новый Структура;
Свойства.Вставить(Свойство, Значение);
УстановитьСвойстваОбработчика(ИмяОбработчика, Свойства);
КонецПроцедуры
Процедура УстановитьСвойстваОбработчика(ИмяОбработчика, Свойства)
Если Свойства.Количество() = 0 Тогда
Возврат;
КонецЕсли;
НаборЗаписей = Неопределено;
Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
НаборЗаписей = РегистрыСведений.ОбработчикиОбновления.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ИмяОбработчика.Установить(ИмяОбработчика);
НаборЗаписей.Прочитать();
КонецЕсли;
ДоступноЧтениеНеразделенныхДанных = Не ОбщегоНазначения.РазделениеВключено()
Или Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных();
Если ДоступноЧтениеНеразделенныхДанных И (НаборЗаписей = Неопределено Или НаборЗаписей.Количество() = 0) Тогда
НаборЗаписей = РегистрыСведений.ОбработчикиОбновленияОбщихДанных.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ИмяОбработчика.Установить(ИмяОбработчика);
НаборЗаписей.Прочитать();
КонецЕсли;
Если НаборЗаписей.Количество() = 0 Тогда
Возврат;
КонецЕсли;
Запись = НаборЗаписей[0];
Для Каждого Свойство Из Свойства Цикл
Запись[Свойство.Ключ] = Свойство.Значение;
КонецЦикла;
НаборЗаписей.Записать();
КонецПроцедуры
////////////////////////////////////////////////////////////////////////////////
// Протоколирование хода обновления.
// Возвращает строковую константу для формирования сообщений журнала регистрации.
//
// Возвращаемое значение:
// Строка
//
Функция СобытиеЖурналаРегистрации() Экспорт
Возврат НСтр("ru = 'Обновление информационной базы'", ОбщегоНазначения.КодОсновногоЯзыка());
КонецФункции
// Возвращает строковую константу для формирования сообщений журнала регистрации
// протоколирования хода выполнения обработчиков обновления.
//
// Возвращаемое значение:
// Строка
//
Функция СобытиеЖурналаРегистрацииПротокол() Экспорт
Возврат СобытиеЖурналаРегистрации() + "." + НСтр("ru = 'Протокол выполнения'", ОбщегоНазначения.КодОсновногоЯзыка());
КонецФункции
////////////////////////////////////////////////////////////////////////////////
// Описание обновлений
// Формирует табличный документ с описанием изменений в версиях,
// которые соответствуют переданному списку версий Разделы.
//
Функция ДокументОписаниеОбновлений(Знач Разделы) Экспорт
ДокументОписаниеОбновлений = Новый ТабличныйДокумент();
Если Разделы.Количество() = 0 Тогда
Возврат ДокументОписаниеОбновлений;
КонецЕсли;
МакетОписаниеОбновлений = Метаданные.ОбщиеМакеты.Найти("ОписаниеИзмененийСистемы");
Если МакетОписаниеОбновлений <> Неопределено Тогда
МакетОписаниеОбновлений = ПолучитьОбщийМакет(МакетОписаниеОбновлений);
Иначе
Возврат Новый ТабличныйДокумент();
КонецЕсли;
Для Каждого Версия Из Разделы Цикл
ВывестиОписаниеИзменений(Версия, ДокументОписаниеОбновлений, МакетОписаниеОбновлений);
КонецЦикла;
Возврат ДокументОписаниеОбновлений;
КонецФункции
// Возвращает массив версий больше последней отображавшейся версии,
// для которых есть описания изменений системы.
//
// Возвращаемое значение:
// Массив - содержит строки с версиями.
//
Функция НеотображавшиесяРазделыОписанияИзменений() Экспорт
Разделы = РазделыОписанияИзменений();
ПоследняяВерсия = ПоследняяВерсияОтображенияИзмененийСистемы();
Если ПоследняяВерсия = Неопределено Тогда
Возврат Новый Массив;
КонецЕсли;
Возврат ПолучитьВерсииБольшеЗаданной(Разделы, ПоследняяВерсия);
КонецФункции
// Устанавливает флаг отображения описаний изменений версий по
// текущую версию включительно.
//
// Параметры:
// ИмяПользователя - Строка - имя пользователя, для которого
// необходимо установить флаг.
//
Процедура УстановитьФлагОтображенияОписанийПоТекущуюВерсию(Знач ИмяПользователя = Неопределено) Экспорт
ОбщегоНазначения.ХранилищеОбщихНастроекСохранить("ОбновлениеИБ",
"ПоследняяВерсияОтображенияИзмененийСистемы", Метаданные.Версия, , ИмяПользователя);
Если ИмяПользователя = Неопределено И Пользователи.ЭтоПолноправныйПользователь() Тогда
ОбщегоНазначения.ХранилищеОбщихНастроекУдалить("ОбновлениеИБ", "ВывестиОписаниеИзмененийДляАдминистратора", ИмяПользователя());
КонецЕсли;
КонецПроцедуры
////////////////////////////////////////////////////////////////////////////////
// Механизм отложенного обновления.
// Планирует выполнение отложенного обновления в клиент-серверной базе.
//
Процедура ЗапланироватьОтложенноеОбновление()
// Планирование выполнения регламентного задания.
// При работе в модели сервиса - добавляется регламентное задание в очередь.
Если Не ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда
ПриВключенииОтложенногоОбновления(Истина);
КонецЕсли;
КонецПроцедуры
// Управляет процессом выполнения отложенных обработчиков обновления.
//
Процедура ВыполнитьОтложенноеОбновление() Экспорт
ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания();
Если ОбновлениеИнформационнойБазыСлужебныйПовтИсп.НеобходимоОбновлениеИнформационнойБазы() Тогда
Возврат;
КонецЕсли;
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
Если СведенияОбОбновлении.ВремяОкончаниеОтложенногоОбновления <> Неопределено Тогда
ОтключитьОтложенноеОбновление();
Возврат;
КонецЕсли;
Если СведенияОбОбновлении.ВремяНачалаОтложенногоОбновления = Неопределено Тогда
СведенияОбОбновлении.ВремяНачалаОтложенногоОбновления = ТекущаяДатаСеанса();
КонецЕсли;
Если ТипЗнч(СведенияОбОбновлении.НомерСеанса) <> Тип("СписокЗначений") Тогда
СведенияОбОбновлении.НомерСеанса = Новый СписокЗначений;
КонецЕсли;
СведенияОбОбновлении.НомерСеанса.Добавить(НомерСеансаИнформационнойБазы());
СведенияОбОбновлении.ДатаНачалаСеансаОбновления = ТекущаяДатаСеанса();
ЗаписатьСведенияОбОбновленииИнформационнойБазы(СведенияОбОбновлении);
// В сеансе регламентного задания проверка дат запрета изменения и загрузки отключается.
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ДатыЗапретаИзменения") Тогда
МодульДатыЗапретаИзменения = ОбщегоНазначения.ОбщийМодуль("ДатыЗапретаИзменения");
МодульДатыЗапретаИзменения.ОтключитьПроверкуДатЗапрета(Истина);
КонецЕсли;
ОбработчикиВыполнялись = Истина;
ДатаПоследнейПроверки = Неопределено;
Попытка
Если ФорсироватьОбновление(СведенияОбОбновлении) Тогда
Группы = НовоеОписаниеГруппПотоковОбработчиковОтложенногоОбновления();
ОтменитьВыполнениеВсехПотоков(Группы);
Пока ОбработчикиВыполнялись Цикл
Поток = ДобавитьПотокОбработчикаОтложенногоОбновления(СведенияОбОбновлении);
Если ТипЗнч(Поток) = Тип("СтрокаТаблицыЗначений") Тогда
ВыполнитьПоток(Группы, Поток);
ОжидатьСвободныйПоток(Группы);
ИначеЕсли Поток = Истина Тогда
ОжидатьЗавершениеЛюбогоПотока(Группы);
ИначеЕсли Поток = Ложь Тогда
ОбработчикиВыполнялись = Ложь;
ОжидатьЗавершениеВсехПотоков(Группы);
Прервать;
КонецЕсли;
Если ДатаПоследнейПроверки = Неопределено
Или ТекущаяДатаСеанса() - ДатаПоследнейПроверки > 600 Тогда
ДатаПоследнейПроверки = ТекущаяДатаСеанса();
ОчиститьПрогрессОбработкиЗаИнтервалыПредыдущегоДня();
КонецЕсли;
Задание = РегламентныеЗаданияСервер.Задание(Метаданные.РегламентныеЗадания.ОтложенноеОбновлениеИБ);
ТребуетсяВыполнение = Задание.Расписание.ТребуетсяВыполнение(ТекущаяДатаСеанса());
Если Не ТребуетсяВыполнение Или Не ФорсироватьОбновление(СведенияОбОбновлении) Тогда
ОжидатьЗавершениеВсехПотоков(Группы);
УдалитьВсеПотокиОбновления();
Прервать;
КонецЕсли;
КонецЦикла;
Иначе
ОчиститьПрогрессОбработкиЗаИнтервалыПредыдущегоДня();
ОбработчикиВыполнялись = ВыполнитьОтложенныйОбработчикОбновления();
КонецЕсли;
Исключение
ЗаписатьОшибку(ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ОтменитьВыполнениеВсехПотоков(Группы);
УдалитьВсеПотокиОбновления();
КонецПопытки;
Если Не ОбработчикиВыполнялись Или ВыполненыВсеОтложенныеОбработчики(СведенияОбОбновлении) Тогда
УдалитьВсеПотокиОбновления();
ОтключитьОтложенноеОбновление();
КонецЕсли;
КонецПроцедуры
Процедура ОчиститьПрогрессОбработкиЗаИнтервалыПредыдущегоДня()
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ИнтервалЧас", НачалоДня(ТекущаяДатаСеанса()));
Запрос.Текст =
"ВЫБРАТЬ
| ПрогрессОбновления.ИмяОбработчика КАК ИмяОбработчика,
| ПрогрессОбновления.ИнтервалЧас КАК ИнтервалЧас,
| ПрогрессОбновления.КлючЗаписи КАК КлючЗаписи
|ИЗ
| РегистрСведений.ПрогрессОбновления КАК ПрогрессОбновления
|ГДЕ
| ПрогрессОбновления.ИнтервалЧас < &ИнтервалЧас";
Результат = Запрос.Выполнить().Выгрузить();
Для Каждого Строка Из Результат Цикл
МенеджерЗаписи = РегистрыСведений.ПрогрессОбновления.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ИмяОбработчика = Строка.ИмяОбработчика;
МенеджерЗаписи.ИнтервалЧас = Строка.ИнтервалЧас;
МенеджерЗаписи.КлючЗаписи = Строка.КлючЗаписи;
МенеджерЗаписи.Удалить();
КонецЦикла;
КонецПроцедуры
Функция ОбработчикиДляОтложеннойРегистрацииДанных(БезФильтра = Ложь, ПерезапускОбновления = Ложь, РегистрируемыеОбработчики = Неопределено) Экспорт
Если РегистрируемыеОбработчики = Неопределено Тогда
РегистрируемыеОбработчики = Новый Массив;
КонецЕсли;
ЭтоПодчиненныйУзелРИБСФильтром = ОбщегоНазначения.ЭтоПодчиненныйУзелРИБСФильтром();
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("РежимВыполненияОбработчика", Перечисления.РежимыВыполненияОтложенныхОбработчиков.Параллельно);
Запрос.УстановитьПараметр("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Отложенно);
Запрос.УстановитьПараметр("БезФильтра", БезФильтра);
Запрос.УстановитьПараметр("ЭтоПодчиненныйУзелРИБСФильтром", ЭтоПодчиненныйУзелРИБСФильтром);
// Отборы для перезапуска отложенного обновления.
Запрос.УстановитьПараметр("СтатусОбработчика", Перечисления.СтатусыОбработчиковОбновления.Выполнен);
Запрос.УстановитьПараметр("РегистрируемыеОбработчики", РегистрируемыеОбработчики);
Запрос.УстановитьПараметр("ОтключитьОтбор", (Не ПерезапускОбновления Или РегистрируемыеОбработчики.Количество() = 0));
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.ИмяОбработчика КАК ИмяОбработчика,
| ОбработчикиОбновления.ИмяБиблиотеки КАК ИмяБиблиотеки,
| ОбработчикиОбновления.Версия КАК Версия,
| ОбработчикиОбновления.ПроцедураЗаполненияДанныхОбновления КАК ПроцедураЗаполненияДанныхОбновления,
| ОбработчикиОбновления.ОчередьОтложеннойОбработки КАК ОчередьОтложеннойОбработки,
| ОбработчикиОбновления.Многопоточный КАК Многопоточный,
| ОбработчикиОбновления.ОбрабатываемыеДанные КАК ОбрабатываемыеДанные,
| ОбработчикиОбновления.Статус КАК Статус
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.РежимВыполнения = &РежимВыполнения
| И (ОбработчикиОбновления.РежимВыполненияОтложенногоОбработчика = &РежимВыполненияОбработчика
| ИЛИ &БезФильтра)
| И (ОбработчикиОбновления.Статус <> &СтатусОбработчика
| ИЛИ ОбработчикиОбновления.ИмяОбработчика В(&РегистрируемыеОбработчики)
| ИЛИ &ОтключитьОтбор)
| И (&ЭтоПодчиненныйУзелРИБСФильтром
| И ОбработчикиОбновления.ЗапускатьИВПодчиненномУзлеРИБСФильтрами
| ИЛИ НЕ &ЭтоПодчиненныйУзелРИБСФильтром)
|
|УПОРЯДОЧИТЬ ПО
| ОбработчикиОбновления.ОчередьОтложеннойОбработки";
Обработчики = Запрос.Выполнить().Выгрузить();
Возврат Обработчики;
КонецФункции
Функция НайтиОбработчикОбновления(КонтекстОбработчика, ПараметрыОбновления = Неопределено)
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
// Получение групп, по которым еще не выполнены все обработчики обновления.
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыОбработчиковОбновления.Выполнен);
Запрос.УстановитьПараметр("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Отложенно);
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| ОбработчикиОбновления.ГруппаОбновления КАК ГруппаОбновления
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.Статус <> &Статус
| И ОбработчикиОбновления.РежимВыполнения = &РежимВыполнения";
ГруппыОбработчиковИЗависимость = Запрос.Выполнить().Выгрузить();
// Выбор невыполненных обработчиков обновления.
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыОбработчиковОбновления.Выполнен);
Запрос.УстановитьПараметр("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Отложенно);
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.ИмяОбработчика КАК ИмяОбработчика,
| ОбработчикиОбновления.Статус КАК Статус,
| ОбработчикиОбновления.Версия КАК Версия,
| ОбработчикиОбновления.ИмяБиблиотеки КАК ИмяБиблиотеки,
| ОбработчикиОбновления.ДлительностьОбработки КАК ДлительностьОбработки,
| ОбработчикиОбновления.РежимВыполнения КАК РежимВыполнения,
| ОбработчикиОбновления.ВерсияРегистрации КАК ВерсияРегистрации,
| ОбработчикиОбновления.ВерсияПорядок КАК ВерсияПорядок,
| ОбработчикиОбновления.Идентификатор КАК Идентификатор,
| ОбработчикиОбновления.ЧислоПопыток КАК ЧислоПопыток,
| ОбработчикиОбновления.ИнформацияОбОшибке КАК ИнформацияОбОшибке,
| ОбработчикиОбновления.Комментарий КАК Комментарий,
| ОбработчикиОбновления.Приоритет КАК Приоритет,
| ОбработчикиОбновления.ПроцедураПроверки КАК ПроцедураПроверки,
| ОбработчикиОбновления.ПроцедураЗаполненияДанныхОбновления КАК ПроцедураЗаполненияДанныхОбновления,
| ОбработчикиОбновления.ОчередьОтложеннойОбработки КАК ОчередьОтложеннойОбработки,
| ОбработчикиОбновления.ЗапускатьТолькоВГлавномУзле КАК ЗапускатьТолькоВГлавномУзле,
| ОбработчикиОбновления.ЗапускатьИВПодчиненномУзлеРИБСФильтрами КАК ЗапускатьИВПодчиненномУзлеРИБСФильтрами,
| ОбработчикиОбновления.Многопоточный КАК Многопоточный,
| ОбработчикиОбновления.ОбработкаПорцииЗавершена КАК ОбработкаПорцииЗавершена,
| ОбработчикиОбновления.ГруппаОбновления КАК ГруппаОбновления,
| ОбработчикиОбновления.ИтерацияЗапуска КАК ИтерацияЗапуска,
| ОбработчикиОбновления.ОбрабатываемыеДанные КАК ОбрабатываемыеДанные,
| ОбработчикиОбновления.СтатистикаВыполнения КАК СтатистикаВыполнения,
| ОбработчикиОбновления.РежимВыполненияОтложенногоОбработчика КАК РежимВыполненияОтложенногоОбработчика,
| ОбработчикиОбновления.ИзменяемыеОбъекты КАК ИзменяемыеОбъекты
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.РежимВыполнения = &РежимВыполнения
| И ОбработчикиОбновления.Статус <> &Статус
|
|УПОРЯДОЧИТЬ ПО
| ГруппаОбновления,
| ОчередьОтложеннойОбработки";
Обработчики = Запрос.Выполнить().Выгрузить();
Пока Истина Цикл
Результат = ОбработчикДляВыполнения(Обработчики, ГруппыОбработчиковИЗависимость, СведенияОбОбновлении);
Если Результат.ОбработчикДляВыполнения = Неопределено
И Результат.ЕстьНевыполненные
И Не Результат.ПрерватьВыполнение Тогда
СведенияОбОбновлении.ТекущаяИтерацияОбновления = СведенияОбОбновлении.ТекущаяИтерацияОбновления + 1;
ЗаписатьСведенияОбОбновленииИнформационнойБазы(СведенияОбОбновлении);
Иначе
Прервать;
КонецЕсли;
КонецЦикла;
ОбработчикДляВыполнения = Результат.ОбработчикДляВыполнения;
Если ОбработчикДляВыполнения = Неопределено Или Результат.ПрерватьВыполнение Тогда
Если Результат.ЕстьВыполняющиеся И Не Результат.ПрерватьВыполнение Тогда
Возврат Истина;
Иначе
СведенияОбОбновлении.ВремяОкончаниеОтложенногоОбновления = ТекущаяДатаСеанса();
СведенияОбОбновлении.ОтложенноеОбновлениеЗавершеноУспешно = Результат.ЗавершеноУспешно;
ЗаписатьСведенияОбОбновленииИнформационнойБазы(СведенияОбОбновлении);
Константы.ОтложенноеОбновлениеЗавершеноУспешно.Установить(Результат.ЗавершеноУспешно);
Если Не ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ() Тогда
Константы.ОтложенноеОбновлениеВГлавномУзлеЗавершеноУспешно.Установить(Результат.ЗавершеноУспешно);
КонецЕсли;
Возврат Ложь;
КонецЕсли;
КонецЕсли;
ПараллельныйРежим = (ОбработчикДляВыполнения.РежимВыполненияОтложенногоОбработчика = Перечисления.РежимыВыполненияОтложенныхОбработчиков.Параллельно);
ПараметрыОбновления = ?(ПараметрыОбновления = Неопределено, Новый Структура, ПараметрыОбновления);
ПараметрыОбновления.Вставить("ПараллельныйРежим", ПараллельныйРежим);
Если ПараллельныйРежим Тогда
ПараметрыОбновления.Вставить("ОчередьОбработчиков", ОчередьОбработчиковГруппыОбновления(ОбработчикДляВыполнения.ГруппаОбновления));
ПараметрыОбновления.Вставить("ЕстьОбработчикиГлавногоУзла", ЕстьОбработчикиТолькоГлавногоУзла());
КонецЕсли;
УстановитьПараметрыОбработчикаОбновления(ОбработчикДляВыполнения, Истина, ПараллельныйРежим);
ПередЗапускомПроцедурыОбработкиДанных(КонтекстОбработчика,
ОбработчикДляВыполнения,
ПараметрыОбновления,
СведенияОбОбновлении);
КонтекстОбработчика.ИдентификаторОбработчика = ОбработчикДляВыполнения.Идентификатор;
КонтекстОбработчика.ИмяОбработчика = ОбработчикДляВыполнения.ИмяОбработчика;
КонтекстОбработчика.ПараллельныйРежим = ПараллельныйРежим;
КонтекстОбработчика.ПараметрыОбновления = ПараметрыОбновления;
КонтекстОбработчика.ПараметрыОбработчикаОбновления = ПараметрыСеанса.ПараметрыОбработчикаОбновления;
КонтекстОбработчика.ТекущаяИтерацияОбновления = СведенияОбОбновлении.ТекущаяИтерацияОбновления;
УстановитьПараметрыОбработчикаОбновления(Неопределено);
Возврат ОбработчикДляВыполнения;
КонецФункции
Процедура СброситьСведенияОбОбновлении(СведенияОбОбновлении)
Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Возврат;
КонецЕсли;
Константы.ОтложенноеОбновлениеЗавершеноУспешно.Установить(Ложь);
СведенияОбОбновлении.Вставить("ВремяНачалаОбновления");
СведенияОбОбновлении.Вставить("ВремяОкончанияОбновления");
СведенияОбОбновлении.Вставить("ПродолжительностьОбновления");
СведенияОбОбновлении.Вставить("ВремяНачалаОтложенногоОбновления");
СведенияОбОбновлении.Вставить("ВремяОкончаниеОтложенногоОбновления");
СведенияОбОбновлении.Вставить("НомерСеанса", Новый СписокЗначений());
СведенияОбОбновлении.Вставить("ОтложенноеОбновлениеЗавершеноУспешно");
СведенияОбОбновлении.Вставить("ВыводитьОписаниеОбновлений", Ложь);
СведенияОбОбновлении.Вставить("ПриостановленныеПроцедурыОбновления", Новый Массив);
СведенияОбОбновлении.Вставить("ЗапущенныеПроцедурыОбновления", Новый Массив);
Если СведенияОбОбновлении.УправлениеОтложеннымОбновлением.Свойство("ФорсироватьОбновление") Тогда
СведенияОбОбновлении.Вставить("УправлениеОтложеннымОбновлением", Новый Структура("ФорсироватьОбновление"));
Иначе
СведенияОбОбновлении.Вставить("УправлениеОтложеннымОбновлением", Новый Структура);
КонецЕсли;
СведенияОбОбновлении.Вставить("ТекущаяИтерацияОбновления", 1);
СведенияОбОбновлении.Вставить("ЗависимостьГруппОбработчиков", Новый Соответствие);
СведенияОбОбновлении.ВерсияДереваОбработчиков = Метаданные.Версия;
ЗаписатьСведенияОбОбновленииИнформационнойБазы(СведенияОбОбновлении);
ЗаписатьСведенияОБлокируемыхОбъектах(НовыеСведенияОБлокируемыхОбъектах());
КонецПроцедуры
Процедура ПроверитьСвойстваОтложенногоОбработчика(Знач Обработчик, Знач РежимВыполненияОтложенныхОбработчиков, ТекстОшибок)
Если РежимВыполненияОтложенныхОбработчиков = "Параллельно"
И Не ЗначениеЗаполнено(Обработчик.ПроцедураЗаполненияДанныхОбновления) Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не указана процедура заполнения данных
|отложенного обработчика обновления
|""%1"".'"),
Обработчик.ИмяОбработчика);
ЗаписатьОшибку(ТекстОшибки);
ТекстОшибок = ТекстОшибок + ТекстОшибки + Символы.ПС;
КонецЕсли;
Если Обработчик.МонопольныйРежим = Истина Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'У отложенного обработчика ""%1""
|не должен быть установлен признак ""%2"".'"),
Обработчик.ИмяОбработчика,
"МонопольныйРежим");
ЗаписатьОшибку(ТекстОшибки);
ТекстОшибок = ТекстОшибок + ТекстОшибки + Символы.ПС;
КонецЕсли;
Если РежимВыполненияОтложенныхОбработчиков = "Параллельно" И Обработчик.ЗапускатьТолькоВГлавномУзле
И Обработчик.ЗапускатьИВПодчиненномУзлеРИБСФильтрами Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'У отложенного обработчика ""%1""
|некорректно заполнены значения свойств:
| - ""%2""
| - ""%3"".
|
|Данные свойства не могут одновременно принимать значение ""Истина"".'"),
Обработчик.ИмяОбработчика,
"ЗапускатьТолькоВГлавномУзле",
"ЗапускатьИВПодчиненномУзлеРИБСФильтрами");
ЗаписатьОшибку(ТекстОшибки);
ТекстОшибок = ТекстОшибок + ТекстОшибки + Символы.ПС;
КонецЕсли;
Если Обработчик.ОбщиеДанные = Истина Тогда
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'У отложенного обработчика ""%1""
|указано недопустимое значение свойства ""%2"".
|
|Данное свойство не может принимать значение ""Истина"" у отложенного обработчика.'"),
Обработчик.ИмяОбработчика, "ОбщиеДанные");
ЗаписатьОшибку(ТекстОшибки);
ТекстОшибок = ТекстОшибок + ТекстОшибки + Символы.ПС;
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьУникальностьИдентификаторовОтложенныхОбработчиков(ИтерацииОбновления)
Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Возврат;
КонецЕсли;
ТаблицаПроверкиУникальности = Новый ТаблицаЗначений;
ТаблицаПроверкиУникальности.Колонки.Добавить("Идентификатор");
ТаблицаПроверкиУникальности.Колонки.Добавить("Индекс");
Для Каждого ИтерацияОбновления Из ИтерацииОбновления Цикл
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("РежимВыполнения", "Отложенно");
ТаблицаОбработчиков = ИтерацияОбновления.Обработчики;
Обработчики = ТаблицаОбработчиков.НайтиСтроки(ПараметрыОтбора);
Для Каждого Обработчик Из Обработчики Цикл
Если Не ЗначениеЗаполнено(Обработчик.Идентификатор) Тогда
Продолжить;
КонецЕсли;
СтрокаТаблицы = ТаблицаПроверкиУникальности.Добавить();
СтрокаТаблицы.Идентификатор = Строка(Обработчик.Идентификатор);
СтрокаТаблицы.Индекс = 1;
КонецЦикла;
КонецЦикла;
ИсходноеКоличествоСтрок = ТаблицаПроверкиУникальности.Количество();
ТаблицаПроверкиУникальности.Свернуть("Идентификатор", "Индекс");
ИтоговоеКоличествоСтрок = ТаблицаПроверкиУникальности.Количество();
// Быстрая проверка.
Если ИсходноеКоличествоСтрок = ИтоговоеКоличествоСтрок Тогда
Возврат; // Все идентификаторы уникальны.
КонецЕсли;
ТаблицаПроверкиУникальности.Сортировать("Индекс Убыв");
ТекстСообщения = НСтр("ru = 'Обнаружены отложенные обработчики обновления,
|у которых совпадают уникальные идентификаторы. Следующие идентификаторы не уникальны:'");
Для Каждого СтрокаИдентификатор Из ТаблицаПроверкиУникальности Цикл
Если СтрокаИдентификатор.Индекс = 1 Тогда
Прервать;
Иначе
ТекстСообщения = ТекстСообщения + Символы.ПС + СтрокаИдентификатор.Идентификатор;
КонецЕсли;
КонецЦикла;
ВызватьИсключение ТекстСообщения;
КонецПроцедуры
Процедура ДобавитьОтложенныеОбработчики(ИмяБиблиотеки, ОбработчикиПоВерсиям, ГруппаОбновления, ТекстОшибок, ТекущийРежимВыполнения = "")
ЭтоПодчиненныйУзелРИБ = ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ();
ЭтоПодчиненныйУзелРИБСФильтром = ОбщегоНазначения.ЭтоПодчиненныйУзелРИБСФильтром();
ОписанияПодсистем = СтандартныеПодсистемыПовтИсп.ОписанияПодсистем();
ОписаниеПодсистемы = ОписанияПодсистем.ПоИменам[ИмяБиблиотеки];
ПараллельноСВерсии = ОписаниеПодсистемы.ПараллельноеОтложенноеОбновлениеСВерсии;
РежимВыполненияОтложенныхОбработчиков = ОписаниеПодсистемы.РежимВыполненияОтложенныхОбработчиков;
НаборРазделенныхОбработчиков = РегистрыСведений.ОбработчикиОбновления.СоздатьНаборЗаписей();
НаборРазделенныхОбработчиков.Прочитать();
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
ЗависимостьГруппОбработчиков = СведенияОбОбновлении.ЗависимостьГруппОбработчиков;
ПропуститьПроверку = Ложь;
СоздаватьНовуюИтерацию = Истина;
Итерация = 1;
ЕстьОбработчикиТолькоГлавногоУзла = Ложь;
СведенияОБлокируемыхОбъектах = СведенияОБлокируемыхОбъектах();
Для Каждого СтрокаВерсия Из ОбработчикиПоВерсиям Цикл
ЗаполнитьБлокируемыеОбъекты(СтрокаВерсия, СведенияОБлокируемыхОбъектах);
Если РежимВыполненияОтложенныхОбработчиков = "Последовательно" Тогда
Если ТекущийРежимВыполнения = "Параллельно" Тогда
// У предыдущей библиотеки был параллельный режим, поэтому
// для текущей создаем отдельную группу обновления.
ГруппаОбновления = ГруппаОбновления + 1;
КонецЕсли;
ЗависимостьГруппОбработчиков.Вставить(ГруппаОбновления, Итерация <> 1);
ТекущийРежимВыполнения = "Последовательно";
ИначеЕсли РежимВыполненияОтложенныхОбработчиков = "Параллельно" И Не ЗначениеЗаполнено(ПараллельноСВерсии) Тогда
ЗависимостьГруппОбработчиков.Вставить(ГруппаОбновления, Ложь);
ТекущийРежимВыполнения = "Параллельно";
СоздаватьНовуюИтерацию = Ложь;
ИначеЕсли РежимВыполненияОтложенныхОбработчиков = "Параллельно" И ЗначениеЗаполнено(ПараллельноСВерсии) И Не ПропуститьПроверку Тогда
НомерВерсии = СтрокаВерсия.Версия;
Если НомерВерсии = "*" Тогда
Результат = -1;
ИначеЕсли СтрНачинаетсяС(НомерВерсии, "ОтладкаОбработчика") Тогда
Результат = 1;
Иначе
Результат = ОбщегоНазначенияКлиентСервер.СравнитьВерсии(НомерВерсии, ПараллельноСВерсии);
КонецЕсли;
Если Результат < 0 Тогда
Если ТекущийРежимВыполнения = "Параллельно" Тогда
// У предыдущей библиотеки был параллельный режим, поэтому
// для текущей создаем отдельную группу обновления.
ГруппаОбновления = ГруппаОбновления + 1;
КонецЕсли;
ЗависимостьГруппОбработчиков.Вставить(ГруппаОбновления, Итерация <> 1);
ТекущийРежимВыполнения = "Последовательно";
Иначе
ЗависимостьГруппОбработчиков.Вставить(ГруппаОбновления, Итерация <> 1);
ПропуститьПроверку = Истина;
ТекущийРежимВыполнения = "Параллельно";
СоздаватьНовуюИтерацию = Ложь;
КонецЕсли;
КонецЕсли;
Для Каждого Обработчик Из СтрокаВерсия.Строки Цикл
ПроверитьСвойстваОтложенногоОбработчика(Обработчик, ТекущийРежимВыполнения, ТекстОшибок);
Запись = НаборРазделенныхОбработчиков.Добавить();
ЗаполнитьЗначенияСвойств(Запись, Обработчик, , "РежимВыполнения,ВерсияПорядок");
РежимВыполнения = Перечисления.РежимыВыполненияОбработчиков[Обработчик.РежимВыполнения];
Запись.ВерсияПорядок = СтрокаВерсия.ВерсияПорядок;
Запись.РежимВыполнения = РежимВыполнения;
Запись.Статус = Перечисления.СтатусыОбработчиковОбновления.НеВыполнялся;
Запись.ИмяБиблиотеки = ИмяБиблиотеки;
Запись.ГруппаОбновления = ГруппаОбновления;
Запись.СтатистикаВыполнения = Новый ХранилищеЗначения(Новый Соответствие);
Если ТекущийРежимВыполнения = "Параллельно" Тогда
Запись.РежимВыполненияОтложенногоОбработчика = Перечисления.РежимыВыполненияОтложенныхОбработчиков.Параллельно;
Иначе
Запись.РежимВыполненияОтложенногоОбработчика = Перечисления.РежимыВыполненияОтложенныхОбработчиков.Последовательно;
КонецЕсли;
// Определение значения константы ОтложенноеОбновлениеВГлавномУзлеЗавершеноУспешно.
Если ТекущийРежимВыполнения = "Параллельно" И Не ЭтоПодчиненныйУзелРИБ
И Обработчик.ЗапускатьТолькоВГлавномУзле = Истина Тогда
ЕстьОбработчикиТолькоГлавногоУзла = Истина;
КонецЕсли;
Если ТекущийРежимВыполнения = "Параллельно" И ЭтоПодчиненныйУзелРИБСФильтром
И Не Обработчик.ЗапускатьИВПодчиненномУзлеРИБСФильтрами Тогда
ЕстьОбработчикиТолькоГлавногоУзла = Истина;
// В подчиненном узле РИБ обработчики главного узла не выполняются.
Запись.Статус = Перечисления.СтатусыОбработчиковОбновления.Выполнен;
КонецЕсли;
КонецЦикла;
Если СоздаватьНовуюИтерацию Тогда
ГруппаОбновления = ГруппаОбновления + 1;
КонецЕсли;
Итерация = Итерация + 1;
КонецЦикла;
ЗаписатьСведенияОБлокируемыхОбъектах(СведенияОБлокируемыхОбъектах);
ТекущееЗначение = Константы.ОтложенноеОбновлениеВГлавномУзлеЗавершеноУспешно.Получить();
Константы.ОтложенноеОбновлениеВГлавномУзлеЗавершеноУспешно.Установить(ТекущееЗначение И Не ЕстьОбработчикиТолькоГлавногоУзла);
// АПК:1327-выкл нет конкурентной работы с регистром
НаборРазделенныхОбработчиков.Записать();
// АПК:1327-вкл
ЗаписатьСведенияОбОбновленииИнформационнойБазы(СведенияОбОбновлении);
КонецПроцедуры
Функция НезавершенныеОтложенныеОбработчики(СведенияОбОбновлении)
Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Возврат Неопределено;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Отложенно);
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыОбработчиковОбновления.Выполнен);
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.ИмяОбработчика КАК ИмяОбработчика,
| ОбработчикиОбновления.Статус КАК Статус,
| ОбработчикиОбновления.Версия КАК Версия,
| ОбработчикиОбновления.ИмяБиблиотеки КАК ИмяБиблиотеки,
| ОбработчикиОбновления.ДлительностьОбработки КАК ДлительностьОбработки,
| ОбработчикиОбновления.РежимВыполнения КАК РежимВыполнения,
| ОбработчикиОбновления.ВерсияРегистрации КАК ВерсияРегистрации,
| ОбработчикиОбновления.Идентификатор КАК Идентификатор,
| ОбработчикиОбновления.ЧислоПопыток КАК ЧислоПопыток,
| ОбработчикиОбновления.СтатистикаВыполнения КАК СтатистикаВыполнения,
| ОбработчикиОбновления.ИнформацияОбОшибке КАК ИнформацияОбОшибке,
| ОбработчикиОбновления.Комментарий КАК Комментарий,
| ОбработчикиОбновления.Приоритет КАК Приоритет,
| ОбработчикиОбновления.ПроцедураПроверки КАК ПроцедураПроверки,
| ОбработчикиОбновления.ПроцедураЗаполненияДанныхОбновления КАК ПроцедураЗаполненияДанныхОбновления,
| ОбработчикиОбновления.ОчередьОтложеннойОбработки КАК ОчередьОтложеннойОбработки,
| ОбработчикиОбновления.ЗапускатьТолькоВГлавномУзле КАК ЗапускатьТолькоВГлавномУзле,
| ОбработчикиОбновления.ЗапускатьИВПодчиненномУзлеРИБСФильтрами КАК ЗапускатьИВПодчиненномУзлеРИБСФильтрами,
| ОбработчикиОбновления.Многопоточный КАК Многопоточный,
| ОбработчикиОбновления.ОбработкаПорцииЗавершена КАК ОбработкаПорцииЗавершена,
| ОбработчикиОбновления.ГруппаОбновления КАК ГруппаОбновления,
| ОбработчикиОбновления.ИтерацияЗапуска КАК ИтерацияЗапуска,
| ОбработчикиОбновления.ОбрабатываемыеДанные КАК ОбрабатываемыеДанные
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.РежимВыполнения = &РежимВыполнения
| И ОбработчикиОбновления.Статус <> &Статус";
Обработчики = Запрос.Выполнить().Выгрузить();
ДеревоОбработчиков = СведенияОбОбновлении.ДеревоОбработчиков.Строки;
Если ДеревоОбработчиков.Количество() > 0 Тогда
СведенияОбОбновлении.ДеревоОбработчиков.Колонки.НомерВерсии.Имя = "Версия";
Отбор = Новый Структура;
Отбор.Вставить("Статус", "Выполняется");
Выполняются = ДеревоОбработчиков.НайтиСтроки(Отбор, Истина);
ПеренестиОбработчикиИзКонстанты(Обработчики, Выполняются);
Отбор.Статус = "НеВыполнено";
НеВыполнены = ДеревоОбработчиков.НайтиСтроки(Отбор, Истина);
ПеренестиОбработчикиИзКонстанты(Обработчики, НеВыполнены);
Отбор.Статус = "Ошибка";
ЗавершилисьСОшибкой = ДеревоОбработчиков.НайтиСтроки(Отбор, Истина);
ПеренестиОбработчикиИзКонстанты(Обработчики, ЗавершилисьСОшибкой);
СведенияОбОбновлении.ДеревоОбработчиков = Новый ДеревоЗначений;
КонецЕсли;
Возврат Обработчики
КонецФункции
Процедура ДобавитьНезавершенныеОтложенныеОбработчики(ИтерацияОбновления, ИмяБиблиотеки,
НезавершенныеОтложенныеОбработчики, Обработчики)
Отбор = Новый Структура;
Отбор.Вставить("ИмяБиблиотеки", ИмяБиблиотеки);
НезавершенныеОбработчикиБиблиотеки = НезавершенныеОтложенныеОбработчики.НайтиСтроки(Отбор);
Для Каждого Обработчик Из НезавершенныеОбработчикиБиблиотеки Цикл
НайденныйОбработчик = Обработчики.Найти(Обработчик.ИмяОбработчика, "ИмяОбработчика", Истина);
Если НайденныйОбработчик <> Неопределено Тогда
Продолжить;
КонецЕсли;
Если ЗначениеЗаполнено(Обработчик.Идентификатор) Тогда
НайденныйОбработчик = Обработчики.Найти(Обработчик.Идентификатор, "Идентификатор", Истина);
Если НайденныйОбработчик <> Неопределено Тогда
Продолжить;
КонецЕсли;
КонецЕсли;
// Проверка, что обработчик не был удален.
ДополнительныйОтбор = Новый Структура;
ДополнительныйОтбор.Вставить("РежимВыполнения", "Отложенно");
ДополнительныйОтбор.Вставить("Процедура", Обработчик.ИмяОбработчика);
НайденныйОбработчик = ИтерацияОбновления.Обработчики.НайтиСтроки(ДополнительныйОтбор);
Если НайденныйОбработчик.Количество() = 0 Тогда
Продолжить;
Иначе
НайденныйОбработчик = НайденныйОбработчик[0];
КонецЕсли;
// Необходимо запланировать выполнение незавершенного обработчика.
СтрокаВерсия = Обработчики.Найти(НайденныйОбработчик.Версия, "Версия");
Если СтрокаВерсия = Неопределено Тогда
СтрокаВерсия = Обработчики.Добавить();
СтрокаВерсия.Версия = НайденныйОбработчик.Версия;
КонецЕсли;
НовыйОбработчик = СтрокаВерсия.Строки.Добавить();
ЗаполнитьЗначенияСвойств(НовыйОбработчик, НайденныйОбработчик, , "РежимВыполнения");
НовыйОбработчик.ИмяОбработчика = НайденныйОбработчик.Процедура;
НовыйОбработчик.РежимВыполнения = "Отложенно";
КонецЦикла;
КонецПроцедуры
Процедура ПеренестиОбработчикиИзКонстанты(Приемник, Источник)
Для Каждого Обработчик Из Источник Цикл
НовыйОбработчик = Приемник.Добавить();
ЗаполнитьЗначенияСвойств(НовыйОбработчик, Обработчик);
НовыйОбработчик.РежимВыполнения = Перечисления.РежимыВыполненияОбработчиков.Отложенно;
КонецЦикла;
КонецПроцедуры
Функция ОчередьОбработчиковГруппыОбновления(ГруппаОбновления)
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ГруппаОбновления", ГруппаОбновления);
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.ОчередьОтложеннойОбработки КАК Очередь,
| ОбработчикиОбновления.Идентификатор КАК Идентификатор,
| ОбработчикиОбновления.ИмяОбработчика КАК Обработчик
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.ГруппаОбновления = &ГруппаОбновления";
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Функция ЕстьОбработчикиТолькоГлавногоУзла()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ИСТИНА
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.ЗапускатьТолькоВГлавномУзле = ИСТИНА";
Возврат Запрос.Выполнить().Выгрузить().Количество() > 0;
КонецФункции
// Возвращаемое значение:
// Структура:
// * ОбработчикДляВыполнения - Неопределено
// - СтрокаТаблицыЗначений:
// ** ИмяОбработчика - Строка.
// ** Идентификатор - УникальныйИдентификатор.
// * ЗавершеноУспешно - Булево.
// * ЕстьВыполняющиеся - Булево.
// * ЕстьНевыполненные - Булево.
//
Функция ОбработчикДляВыполнения(Обработчики, ГруппыОбработчиковИЗависимость, СведенияОбОбновлении)
ЗависимостьГруппОбработчиков = СведенияОбОбновлении.ЗависимостьГруппОбработчиков;
ТекущаяИтерация = СведенияОбОбновлении.ТекущаяИтерацияОбновления;
ТекущаяГруппаОбновления = Неопределено;
ОбработчикДляВыполнения = Неопределено;
ПропускаемыеГруппы = Новый Массив;
ЗавершеноУспешно = Истина;
ЕстьВыполняющиеся = Ложь;
ЕстьОшибки = Ложь;
ЕстьНевыполненные = Ложь;
ПрерватьВыполнение = Ложь;
ВыполняющийсяМногопоточныйОбработчик = Неопределено;
Для Каждого Обработчик Из Обработчики Цикл
Если Обработчик.ИтерацияЗапуска = ТекущаяИтерация Тогда
// Обработчик в этой итерации обновления уже запускался.
ЕстьНевыполненные = Истина;
Продолжить;
КонецЕсли;
Если ПропускаемыеГруппы.Найти(Обработчик.ГруппаОбновления) <> Неопределено Тогда
Продолжить;
КонецЕсли;
Если Обработчик.ГруппаОбновления <> 1
И ЗависимостьГруппОбработчиков[Обработчик.ГруппаОбновления] = Истина Тогда
НайденнаяСтрока = ГруппыОбработчиковИЗависимость.Найти(Обработчик.ГруппаОбновления - 1, "ГруппаОбновления");
Если НайденнаяСтрока <> Неопределено Тогда
ПропускаемыеГруппы.Добавить(Обработчик.ГруппаОбновления);
Продолжить;
КонецЕсли;
КонецЕсли;
Если ТекущаяГруппаОбновления = Неопределено Тогда
ТекущаяГруппаОбновления = Обработчик.ГруппаОбновления;
ИначеЕсли ТекущаяГруппаОбновления <> Обработчик.ГруппаОбновления Тогда
// При переходе к следующей группе обновления делается проверка ошибок по предыдущей группе
// и наличия многопоточных обработчиков, для которых есть порция обновления.
Если ВыполняющийсяМногопоточныйОбработчик = Неопределено Тогда
Если ЕстьОшибки Тогда
ЗавершеноУспешно = Ложь;
КонецЕсли;
Иначе
ОбработчикДляВыполнения = ВыполняющийсяМногопоточныйОбработчик;
Прервать;
КонецЕсли;
ТекущаяГруппаОбновления = Обработчик.ГруппаОбновления;
КонецЕсли;
Если Обработчик.Статус = Перечисления.СтатусыОбработчиковОбновления.Выполняется
И Не Обработчик.ОбработкаПорцииЗавершена Тогда
Если Обработчик.Многопоточный Тогда
Если ЕстьПорцииДляОбновления(Обработчик) Тогда
ВыполняющийсяМногопоточныйОбработчик = Обработчик;
КонецЕсли;
ИначеЕсли ПотокиОбновления().Количество() = 0 Тогда
ОбработчикДляВыполнения = Обработчик;
КонецЕсли;
ЕстьВыполняющиеся = Истина;
Продолжить;
КонецЕсли;
Если Обработчик.Статус = Перечисления.СтатусыОбработчиковОбновления.Приостановлен Тогда
Продолжить;
КонецЕсли;
МаксимумПопытокОбновления = МаксимумПопытокОбновления(Обработчик);
Если Обработчик.ЧислоПопыток >= МаксимумПопытокОбновления Тогда
Если Обработчик.Статус = Перечисления.СтатусыОбработчиковОбновления.Ошибка Тогда
ПрерватьВыполнение = Истина;
Продолжить;
ИначеЕсли ВсеОбработчикиЗациклились() Тогда
ОтметитьЗациклившиесяОбработчики();
ПрерватьВыполнение = Истина;
Продолжить;
КонецЕсли;
КонецЕсли;
ОбработчикДляВыполнения = Обработчик;
Прервать;
КонецЦикла;
Если ОбработчикДляВыполнения = Неопределено И ВыполняющийсяМногопоточныйОбработчик <> Неопределено Тогда
ОбработчикДляВыполнения = ВыполняющийсяМногопоточныйОбработчик;
КонецЕсли;
Если ЕстьОшибки Или ПрерватьВыполнение Тогда
ЗавершеноУспешно = Ложь;
КонецЕсли;
Результат = Новый Структура;
Результат.Вставить("ОбработчикДляВыполнения", ОбработчикДляВыполнения);
Результат.Вставить("ЗавершеноУспешно", ЗавершеноУспешно);
Результат.Вставить("ПрерватьВыполнение", ПрерватьВыполнение);
Результат.Вставить("ЕстьВыполняющиеся", ЕстьВыполняющиеся);
Результат.Вставить("ЕстьНевыполненные", ЕстьНевыполненные);
Возврат Результат;
КонецФункции
Функция ОбработчикОбновления(ИмяОбработчика)
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ИмяОбработчика", ИмяОбработчика);
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.ИмяОбработчика КАК ИмяОбработчика,
| ОбработчикиОбновления.Статус КАК Статус,
| ОбработчикиОбновления.Версия КАК Версия,
| ОбработчикиОбновления.ИмяБиблиотеки КАК ИмяБиблиотеки,
| ОбработчикиОбновления.ДлительностьОбработки КАК ДлительностьОбработки,
| ОбработчикиОбновления.РежимВыполнения КАК РежимВыполнения,
| ОбработчикиОбновления.ВерсияРегистрации КАК ВерсияРегистрации,
| ОбработчикиОбновления.ВерсияПорядок КАК ВерсияПорядок,
| ОбработчикиОбновления.Идентификатор КАК Идентификатор,
| ОбработчикиОбновления.ЧислоПопыток КАК ЧислоПопыток,
| ОбработчикиОбновления.СтатистикаВыполнения КАК СтатистикаВыполнения,
| ОбработчикиОбновления.ИнформацияОбОшибке КАК ИнформацияОбОшибке,
| ОбработчикиОбновления.Комментарий КАК Комментарий,
| ОбработчикиОбновления.Приоритет КАК Приоритет,
| ОбработчикиОбновления.ПроцедураПроверки КАК ПроцедураПроверки,
| ОбработчикиОбновления.ПроцедураЗаполненияДанныхОбновления КАК ПроцедураЗаполненияДанныхОбновления,
| ОбработчикиОбновления.ОчередьОтложеннойОбработки КАК ОчередьОтложеннойОбработки,
| ОбработчикиОбновления.ЗапускатьТолькоВГлавномУзле КАК ЗапускатьТолькоВГлавномУзле,
| ОбработчикиОбновления.ЗапускатьИВПодчиненномУзлеРИБСФильтрами КАК ЗапускатьИВПодчиненномУзлеРИБСФильтрами,
| ОбработчикиОбновления.Многопоточный КАК Многопоточный,
| ОбработчикиОбновления.ОбработкаПорцииЗавершена КАК ОбработкаПорцииЗавершена,
| ОбработчикиОбновления.ГруппаОбновления КАК ГруппаОбновления,
| ОбработчикиОбновления.ИтерацияЗапуска КАК ИтерацияЗапуска,
| ОбработчикиОбновления.ОбрабатываемыеДанные КАК ОбрабатываемыеДанные,
| ОбработчикиОбновления.РежимВыполненияОтложенногоОбработчика КАК РежимВыполненияОтложенногоОбработчика
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.ИмяОбработчика = &ИмяОбработчика";
Результат = Запрос.Выполнить().Выгрузить();
Если Результат.Количество() = 0 Тогда
Возврат Неопределено;
Иначе
Возврат Результат[0];
КонецЕсли;
КонецФункции
////////////////////////////////////////////////////////////////////////////////
// Механизм многопоточного обновления.
// Имя группы потоков регистрации данных для отложенного обновления.
//
// Возвращаемое значение:
// Строка - имя группы.
//
Функция ГруппаПотоковРегистрацииДанныхОтложенногоОбновления()
Возврат "Регистрация";
КонецФункции
// Имя группы потоков отложенного обновления.
//
// Возвращаемое значение:
// Строка - имя группы.
//
Функция ГруппаПотоковОтложенногоОбновления()
Возврат "Обновление";
КонецФункции
// Имя группы потоков поиска порций данных для многопоточного выполнения обработчиков обновления.
//
// Возвращаемое значение:
// Строка - имя группы.
//
Функция ГруппаПотоковПоискаПорций()
Возврат "Поиск";
КонецФункции
// Создать новое описание потоков регистрации данных отложенного обновления.
//
// Возвращаемое значение:
// см. НовоеОписаниеПотоков
//
Функция НовоеОписаниеГруппПотоковРегистрацииДанныхОтложенногоОбновления() Экспорт
ГруппаРегистрации = НовоеОписаниеГруппыПотоков();
ГруппаРегистрации.Процедура =
"ОбновлениеИнформационнойБазыСлужебный.ЗаполнитьДанныеОтложенногоОбработчика";
ГруппаРегистрации.ПроцедураЗавершения =
"ОбновлениеИнформационнойБазыСлужебный.ЗавершитьРегистрациюДанныхОтложенногоОбновления";
Группы = Новый Соответствие;
Группы[ГруппаПотоковРегистрацииДанныхОтложенногоОбновления()] = ГруппаРегистрации;
Возврат Группы;
КонецФункции
// Добавить поток регистрации данных отложенного обновления.
//
// Параметры:
// ОписаниеОбрабатываемыхДанных - см. НовоеОписаниеОбрабатываемыхДанных
//
// Возвращаемое значение:
// СтрокаТаблицыЗначений - см. НовоеОписаниеПотоков
//
Функция ДобавитьПотокРегистрацииДанныхОтложенногоОбновления(ОписаниеОбрабатываемыхДанных)
ШаблонНаименования = НСтр("ru = 'Регистрация данных обработчика обновления ""%1""'");
ОписаниеОбрабатываемыхДанных.Статус = "Выполняется";
Поток = НовыйПоток();
Поток.ПараметрыПроцедуры = ОписаниеОбрабатываемыхДанных;
Поток.ПараметрыПроцедурыЗавершения = ОписаниеОбрабатываемыхДанных;
Поток.Группа = ГруппаПотоковРегистрацииДанныхОтложенногоОбновления();
Поток.Наименование = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонНаименования,
ОписаниеОбрабатываемыхДанных.ИмяОбработчика);
СохранитьПотокОбновления(Поток);
Возврат Поток;
КонецФункции
// Завершить регистрацию данных отложенного обновления.
// Вызывается автоматически в основном потоке, после завершения выполнения ЗаполнитьДанныеОтложенногоОбработчика().
//
// Параметры:
// ОписаниеОбрабатываемыхДанных - см. НовоеОписаниеОбрабатываемыхДанных
// АдресРезультата - Строка - адрес временного хранилища с результатом из ЗаполнитьДанныеОтложенногоОбработчика().
//
Процедура ЗавершитьРегистрациюДанныхОтложенногоОбновления(ОписаниеОбрабатываемыхДанных,
АдресРезультата) Экспорт
Результат = ПолучитьИзВременногоХранилища(АдресРезультата);
ЗаполнитьЗначенияСвойств(ОписаниеОбрабатываемыхДанных, Результат);
ОписаниеОбрабатываемыхДанных.Статус = "Выполнено";
Если ЭтоОписаниеДанныхМногопоточногоОбработчика(ОписаниеОбрабатываемыхДанных) Тогда
ИсправитьПолныеИменаВПараметрахВыборки(ОписаниеОбрабатываемыхДанных.ПараметрыВыборки);
КонецЕсли;
ОбрабатываемыеДанные = Новый ХранилищеЗначения(ОписаниеОбрабатываемыхДанных, Новый СжатиеДанных(9));
УстановитьСвойствоОбработчика(ОписаниеОбрабатываемыхДанных.ИмяОбработчика, "ОбрабатываемыеДанные", ОбрабатываемыеДанные);
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда
Если Результат.ДанныеОбновления <> Неопределено Тогда
МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер");
МодульОбменДаннымиСервер.СохранитьДанныеОбновления(Результат.ДанныеОбновления, Результат.ИмяФайлаСИзменениями);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
// Создать новое описание потоков обработчиков отложенного обновления.
//
// Возвращаемое значение:
// см. НовоеОписаниеПотоков
//
Функция НовоеОписаниеГруппПотоковОбработчиковОтложенногоОбновления() Экспорт
ГруппаОбновления = НовоеОписаниеГруппыПотоков();
ГруппаОбновления.Процедура =
"ОбновлениеИнформационнойБазыСлужебный.ВыполнитьОтложенныйОбработчик";
ГруппаОбновления.ПроцедураЗавершения =
"ОбновлениеИнформационнойБазыСлужебный.ЗавершитьВыполнениеОтложенногоОбработчика";
ГруппаОбновления.ПриАварийномЗавершении =
"ОбновлениеИнформационнойБазыСлужебный.ПриАварийномЗавершенииПотокаОтложенногоОбработчика";
ГруппаОбновления.ПриОтменеПотока =
"ОбновлениеИнформационнойБазыСлужебный.ПриОтменеПотокаОтложенногоОбработчика";
ГруппаПоиска = НовоеОписаниеГруппыПотоков();
ГруппаПоиска.Процедура =
"ОбновлениеИнформационнойБазыСлужебный.НайтиПорциюДляОбновления";
ГруппаПоиска.ПроцедураЗавершения =
"ОбновлениеИнформационнойБазыСлужебный.ЗавершитьПоискПорцииДляОбновления";
ГруппаПоиска.ПриАварийномЗавершении =
"ОбновлениеИнформационнойБазыСлужебный.ПриАварийномЗавершенииПотокаПоискаПорцииДляОбновления";
ГруппаПоиска.ПриОтменеПотока =
"ОбновлениеИнформационнойБазыСлужебный.ПриОтменеПотокаПоискаПорцииДляОбновления";
Группы = Новый Соответствие;
Группы[ГруппаПотоковОтложенногоОбновления()] = ГруппаОбновления;
Группы[ГруппаПотоковПоискаПорций()] = ГруппаПоиска;
Возврат Группы;
КонецФункции
Функция НовыйПоток()
Потоки = НовоеОписаниеПотоков();
Поток = Потоки.Добавить();
Поток.ИдентификаторПотока = Новый УникальныйИдентификатор;
Возврат Поток;
КонецФункции
// Добавить поток обработчика отложенного обновления.
//
// Параметры:
// ОписаниеПотоков - см. НовоеОписаниеПотоковОбработчиковОтложенногоОбновления
// СведенияОбОбновлении - см. СведенияОбОбновленииИнформационнойБазы
//
// Возвращаемое значение:
// СтрокаТаблицыЗначений - см. НовоеОписаниеПотоков
// Булево - Истина, если обработчик не нужно выполнять или Ложь, если выполнение обработчиков нужно завершить.
//
Функция ДобавитьПотокОбработчикаОтложенногоОбновления(СведенияОбОбновлении)
Поток = Неопределено;
Пока Поток = Неопределено Цикл
КонтекстОбработчика = НовыйКонтекстОбработчика();
ОбработчикОбновления = НайтиОбработчикОбновления(КонтекстОбработчика);
Если ТипЗнч(ОбработчикОбновления) = Тип("СтрокаТаблицыЗначений") Тогда
Если КонтекстОбработчика.ВыполнитьОбработчик Тогда
Поток = НовыйПоток();
Если ОбработчикОбновления.Многопоточный Тогда
ДополнитьКонтекстМногопоточногоОбработчика(КонтекстОбработчика);
Добавлен = ДобавитьПотокПоискаДанныхДляОбновления(Поток,
ОбработчикОбновления,
КонтекстОбработчика,
СведенияОбОбновлении);
Если Не Добавлен Тогда
Поток = Истина;
КонецЕсли;
Иначе
ДобавитьПотокОбработчикаОбновления(Поток, КонтекстОбработчика);
КонецЕсли;
Иначе
ЗавершитьВыполнениеОтложенногоОбработчика(КонтекстОбработчика, Неопределено);
Поток = Неопределено;
КонецЕсли;
Иначе
Поток = ОбработчикОбновления;
КонецЕсли;
КонецЦикла;
Возврат Поток;
КонецФункции
// Добавить поток поиска данных для обработчика отложенного обновления.
//
// Параметры:
// Поток - см. НовоеОписаниеПотоков
// Обработчик - СтрокаДереваЗначений - обработчик обновления в виде строки дерева обработчиков.
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
// СведенияОбОбновлении - см. СведенияОбОбновленииИнформационнойБазы
//
// Возвращаемое значение:
// Булево - Истина, поток добавлен, иначе Ложь.
//
Функция ДобавитьПотокПоискаДанныхДляОбновления(Поток, Обработчик, КонтекстОбработчика, СведенияОбОбновлении)
ИмяОбработчика = Обработчик.ИмяОбработчика;
Описание = Обработчик.ОбрабатываемыеДанные.Получить();
Если Не Описание.ВыполняетсяПоискПорции Тогда
ПорцииДляОбновления = Описание.ПорцииДляОбновления;
Если Описание.ПоискЗавершен И (ПорцииДляОбновления = Неопределено Или ПорцииДляОбновления.Количество() = 0) Тогда
ПорцииДляОбновления = Неопределено;
Описание.ПоследняяВыбраннаяЗапись = Неопределено;
Описание.ПоискЗавершен = Ложь;
КонецЕсли;
ШаблонНаименования = НСтр("ru = 'Поиск данных для обработчика обновления ""%1""'");
Поток.Наименование = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонНаименования, ИмяОбработчика);
Поток.Группа = ГруппаПотоковПоискаПорций();
Поток.ПриоритетЗавершения = 1;
ПараметрыПоиска = НовыеПараметрыПоискаПорции();
ПараметрыПоиска.ИмяОбработчика = ИмяОбработчика;
ПараметрыПоиска.КонтекстОбработчика = КонтекстОбработчика;
ПараметрыПоиска.ПараметрыВыборки = Описание.ПараметрыВыборки;
ПараметрыПоиска.Очередь = КонтекстОбработчика.Параметры.Очередь;
ПараметрыПоиска.ФорсироватьОбновление = ФорсироватьОбновление(СведенияОбОбновлении);
НеобработаннаяПорция = ПерваяНеобработаннаяПорция(ПорцииДляОбновления);
Если НеобработаннаяПорция <> Неопределено Тогда
ПараметрыПоиска.ИдентификаторПорции = НеобработаннаяПорция.Идентификатор;
ПараметрыПоиска.ПерваяЗапись = НеобработаннаяПорция.ПерваяЗапись;
ПараметрыПоиска.ПоследняяЗапись = НеобработаннаяПорция.ПоследняяЗапись;
ИначеЕсли Описание.ПоследняяВыбраннаяЗапись <> Неопределено Тогда
ПараметрыПоиска.ПоследняяВыбраннаяЗапись = Описание.ПоследняяВыбраннаяЗапись;
КонецЕсли;
Поток.ПараметрыПроцедуры = ПараметрыПоиска;
Поток.ПараметрыПроцедурыЗавершения = ПараметрыПоиска;
Описание.ВыполняетсяПоискПорции = Истина;
НачатьТранзакцию();
Попытка
УстановитьСвойствоОбработчика(ИмяОбработчика,
"ОбрабатываемыеДанные",
Новый ХранилищеЗначения(Описание));
СохранитьПотокОбновления(Поток);
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
Возврат Истина;
Иначе
Возврат Ложь;
КонецЕсли;
КонецФункции
// Добавить поток обработчика отложенного обновления.
//
// Параметры:
// Поток - см. НовоеОписаниеПотоков
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
//
Процедура ДобавитьПотокОбработчикаОбновления(Поток, КонтекстОбработчика)
ИмяОбработчика = КонтекстОбработчика.ИмяОбработчика;
ШаблонНаименования = НСтр("ru = 'Выполнение обработчика обновления ""%1""'");
Поток.Наименование = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонНаименования, ИмяОбработчика);
Поток.Группа = ГруппаПотоковОтложенногоОбновления();
Поток.ПараметрыПроцедуры = КонтекстОбработчика;
Поток.ПараметрыПроцедурыЗавершения = КонтекстОбработчика;
СохранитьПотокОбновления(Поток);
КонецПроцедуры
// Выполнить отложенный обработчик в фоновом задании.
// Выполняется только, если КонтекстОбработчика.ВыполнитьОбработчик = Истина (т.е. не в подчиненном узле РИБ).
//
// Параметры:
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
// АдресРезультата - Строка - адрес временного хранилища для сохранения результата выполнения процедуры.
//
Процедура ВыполнитьОтложенныйОбработчик(КонтекстОбработчика, АдресРезультата) Экспорт
ПараметрыСеанса.ПараметрыОбработчикаОбновления = КонтекстОбработчика.ПараметрыОбработчикаОбновления;
ПодсистемаСуществует = ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом");
ОтключитьОбновлениеКлючейДоступа(Истина, ПодсистемаСуществует);
Попытка
ПараметрыВызова = Новый Массив;
ПараметрыВызова.Добавить(КонтекстОбработчика.Параметры);
Результат = НовыйРезультатВыполненияОтложенногоОбработчика();
Если КонтекстОбработчика.Параметры.Свойство("ОбновляемыеДанные") Тогда
ВсегоДанных = 0;
Для Каждого СтрокаОбновляемыйОбъект Из КонтекстОбработчика.Параметры.ОбновляемыеДанные.НаборДанных Цикл
ВсегоДанных = ВсегоДанных + СтрокаОбновляемыйОбъект.Данные.Количество();
КонецЦикла;
Результат.ПереданоДанныхДляОбработки = ВсегоДанных;
КонецЕсли;
Результат.НачалоПроцедурыОбработчика = ТекущаяУниверсальнаяДатаВМиллисекундах();
ОбщегоНазначения.ВыполнитьМетодКонфигурации(КонтекстОбработчика.ИмяОбработчика, ПараметрыВызова);
Результат.ЗавершениеПроцедурыОбработчика = ТекущаяУниверсальнаяДатаВМиллисекундах();
Результат.Параметры = КонтекстОбработчика.Параметры;
Результат.ПараметрыОбработчикаОбновления = ПараметрыСеанса.ПараметрыОбработчикаОбновления;
Попытка
ПроверитьВложеннуюТранзакцию(КонтекстОбработчика.ТранзакцияАктивнаНаНачалоВыполнения,
КонтекстОбработчика.ИмяОбработчика);
Исключение
Результат.ИнформацияОбОшибке = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
Результат.ЕстьНеЗакрытыеТранзакции = Истина;
Пока ТранзакцияАктивна() Цикл
ОтменитьТранзакцию();
КонецЦикла;
КонецПопытки;
ПоместитьВоВременноеХранилище(Результат, АдресРезультата);
ОтключитьОбновлениеКлючейДоступа(Ложь, ПодсистемаСуществует);
ПараметрыСеанса.ПараметрыОбработчикаОбновления = Новый ФиксированнаяСтруктура(НовыеПараметрыОбработчикаОбновления());
Исключение
ОтключитьОбновлениеКлючейДоступа(Ложь, ПодсистемаСуществует);
ПараметрыСеанса.ПараметрыОбработчикаОбновления = Новый ФиксированнаяСтруктура(НовыеПараметрыОбработчикаОбновления());
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
// Завершить выполнение отложенного обработчика.
// Вызывается автоматически в основном потоке, после завершения выполнения ВыполнитьОтложенныйОбработчик().
//
// Параметры:
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
// АдресРезультата - Строка - адрес временного хранилища с результатом из ВыполнитьОтложенныйОбработчик().
// СведенияОбОбновлении - см. СведенияОбОбновленииИнформационнойБазы
//
Процедура ЗавершитьВыполнениеОтложенногоОбработчика(КонтекстОбработчика, АдресРезультата) Экспорт
КонтекстОбработчика.Вставить("ПропуститьОтменуТранзакций");
НачатьТранзакцию();
Попытка
ОбработчикОбновления = ОбработчикОбновления(КонтекстОбработчика.ИмяОбработчика);
УстановитьСвойствоОбработчика(ОбработчикОбновления.ИмяОбработчика, "ОбработкаПорцииЗавершена", Истина);
ЗагрузитьРезультатВыполненияОбработчика(КонтекстОбработчика, АдресРезультата);
ПараметрыСеанса.ПараметрыОбработчикаОбновления = КонтекстОбработчика.ПараметрыОбработчикаОбновления;
Если КонтекстОбработчика.ЗапускВыполненБезОшибок Тогда
ПослеЗапускаПроцедурыОбработкиДанных(КонтекстОбработчика, КонтекстОбработчика.ИмяОбработчика);
КонецЕсли;
ЗавершитьПроцедуруОбработкиДанных(КонтекстОбработчика, КонтекстОбработчика.ИмяОбработчика);
ПараметрыСеанса.ПараметрыОбработчикаОбновления = Новый ФиксированнаяСтруктура(НовыеПараметрыОбработчикаОбновления());
Если ОбработчикОбновления.Многопоточный Тогда
ЗавершитьВыполнениеМногопоточногоОбработчика(КонтекстОбработчика, КонтекстОбработчика.ИмяОбработчика);
КонецЕсли;
ЗавершитьВыполнениеОтложенногоОбработчикаОбновления(КонтекстОбработчика);
РассчитатьВремяВыполненияПроцедурыОбработчика(КонтекстОбработчика, КонтекстОбработчика.ИмяОбработчика);
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонтекстОбработчика.Удалить("ПропуститьОтменуТранзакций");
Если КонтекстОбработчика.Свойство("ОшибкаПриЗавершенииОбработчика") Тогда
ВызватьИсключение КонтекстОбработчика.ОшибкаПриЗавершенииОбработчика;
КонецЕсли;
КонецПроцедуры
// Рассчитать время выполнения процедуры обработки данных (не всего обработчика).
//
// Параметры:
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
// ИмяОбработчика - Строка
//
Процедура РассчитатьВремяВыполненияПроцедурыОбработчика(КонтекстОбработчика, ИмяОбработчика)
ОбработчикОбновления = ОбработчикОбновления(ИмяОбработчика);
НачалоПроцедурыОбработчика = ?(КонтекстОбработчика.НачалоПроцедурыОбработчика = Неопределено, 0,
КонтекстОбработчика.НачалоПроцедурыОбработчика);
ЗавершениеПроцедурыОбработчика = ?(КонтекстОбработчика.ЗавершениеПроцедурыОбработчика = Неопределено, 0,
КонтекстОбработчика.ЗавершениеПроцедурыОбработчика);
ПереданоДанныхДляОбработки = ?(КонтекстОбработчика.ПереданоДанныхДляОбработки = Неопределено, 0,
КонтекстОбработчика.ПереданоДанныхДляОбработки);
ДлительностьПроцедурыОбработчика = ЗавершениеПроцедурыОбработчика - НачалоПроцедурыОбработчика;
НачалоВыполнения = '00010101' + НачалоПроцедурыОбработчика / 1000;
ЗавершениеВыполнения = '00010101' + ЗавершениеПроцедурыОбработчика / 1000;
СтатистикаВыполнения = ОбработчикОбновления.СтатистикаВыполнения.Получить();
СтатистикаНачало = СтатистикаВыполнения["НачалоПроцедурыОбработчика"];
СтатистикаЗавершение = СтатистикаВыполнения["ЗавершениеПроцедурыОбработчика"];
СтатистикаДанныхДляОбработки = СтатистикаВыполнения["ПереданоДанныхДляОбработки"];
СтатистикаДлительность = СтатистикаВыполнения["ДлительностьПроцедурыОбработчика"];
Если СтатистикаНачало = Неопределено Тогда
СтатистикаНачало = Новый Массив;
СтатистикаВыполнения["НачалоПроцедурыОбработчика"] = СтатистикаНачало;
КонецЕсли;
Если СтатистикаЗавершение = Неопределено Тогда
СтатистикаЗавершение = Новый Массив;
СтатистикаВыполнения["ЗавершениеПроцедурыОбработчика"] = СтатистикаЗавершение;
КонецЕсли;
Если СтатистикаДанныхДляОбработки = Неопределено Тогда
СтатистикаДанныхДляОбработки = Новый Массив;
СтатистикаВыполнения["ПереданоДанныхДляОбработки"] = СтатистикаДанныхДляОбработки;
КонецЕсли;
Если СтатистикаДлительность = Неопределено Тогда
СтатистикаДлительность = Новый Массив;
СтатистикаВыполнения["ДлительностьПроцедурыОбработчика"] = СтатистикаДлительность;
КонецЕсли;
СтатистикаНачало.Добавить(НачалоВыполнения);
СтатистикаЗавершение.Добавить(ЗавершениеВыполнения);
СтатистикаДанныхДляОбработки.Добавить(ПереданоДанныхДляОбработки);
СтатистикаДлительность.Добавить(ДлительностьПроцедурыОбработчика);
УстановитьСвойствоОбработчика(ОбработчикОбновления.ИмяОбработчика,
"СтатистикаВыполнения",
Новый ХранилищеЗначения(СтатистикаВыполнения));
КонецПроцедуры
// Обработчик аварийного завершения выполнения потока отложенного обновления.
//
// Параметры:
// Поток - см. НовоеОписаниеПотоков
// ИнформацияОбОшибке - ИнформацияОбОшибке - описание возникшей ошибки.
//
Процедура ПриАварийномЗавершенииПотокаОтложенногоОбработчика(Поток, ИнформацияОбОшибке) Экспорт
ОбработчикОбновления = ОбработчикОбновления(Поток.ПараметрыПроцедуры.ИмяОбработчика);
УстановитьСвойствоОбработчика(ОбработчикОбновления.ИмяОбработчика, "ОбработкаПорцииЗавершена", Истина);
ОбработатьИсключениеОбработчика(Поток.ПараметрыПроцедуры, ОбработчикОбновления, ИнформацияОбОшибке);
Если ОбработчикОбновления.Многопоточный Тогда
ОтменитьОбработкуДанныхМногопоточногоОбработчика(Поток, ОбработчикОбновления);
КонецЕсли;
КонтекстОбработчика = Поток.ПараметрыПроцедурыЗавершения;
ЗавершитьВыполнениеОтложенногоОбработчикаОбновления(КонтекстОбработчика);
КонецПроцедуры
// Обработчик отмены выполнения потока.
//
// Параметры:
// Поток - см. НовоеОписаниеПотоков
//
Процедура ПриОтменеПотокаОтложенногоОбработчика(Поток) Экспорт
ОбработчикОбновления = ОбработчикОбновления(Поток.ПараметрыПроцедуры.ИмяОбработчика);
УстановитьСвойствоОбработчика(ОбработчикОбновления.ИмяОбработчика, "ОбработкаПорцииЗавершена", Истина);
Если ОбработчикОбновления.Статус = Перечисления.СтатусыОбработчиковОбновления.Выполняется Тогда
УстановитьСтатусОбработчика(ОбработчикОбновления.ИмяОбработчика, "НеВыполнялся");
КонецЕсли;
Если ОбработчикОбновления.Многопоточный Тогда
ОтменитьОбработкуДанныхМногопоточногоОбработчика(Поток, ОбработчикОбновления);
КонецЕсли;
КонецПроцедуры
// Загрузить результат выполнения обработчика из временного хранилища в контекст обработчика обновления.
//
// Параметры:
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
// АдресРезультата - Строка - адрес результата во временном хранилище.
//
Процедура ЗагрузитьРезультатВыполненияОбработчика(КонтекстОбработчика, АдресРезультата)
Если АдресРезультата <> Неопределено Тогда
Результат = ПолучитьИзВременногоХранилища(АдресРезультата); // см. НовыйРезультатВыполненияОтложенногоОбработчика
Иначе
Результат = Неопределено;
КонецЕсли;
Если Результат <> Неопределено Тогда
Если КонтекстОбработчика.ЗаписыватьВЖурнал Тогда
КонтекстОбработчика.ДетальноеОписаниеОбработчика.Параметры = Результат.Параметры;
КонецЕсли;
КонтекстОбработчика.ЕстьНеЗакрытыеТранзакции = Результат.ЕстьНеЗакрытыеТранзакции;
КонтекстОбработчика.ЗавершениеПроцедурыОбработчика = Результат.ЗавершениеПроцедурыОбработчика;
КонтекстОбработчика.ИнформацияОбОшибке = Результат.ИнформацияОбОшибке;
КонтекстОбработчика.НачалоПроцедурыОбработчика = Результат.НачалоПроцедурыОбработчика;
КонтекстОбработчика.ПереданоДанныхДляОбработки = Результат.ПереданоДанныхДляОбработки;
КонтекстОбработчика.Параметры = Результат.Параметры;
КонтекстОбработчика.ПараметрыОбработчикаОбновления = Результат.ПараметрыОбработчикаОбновления;
КонецЕсли;
КонецПроцедуры
Процедура УдалитьВсеПотокиОбновления()
НаборЗаписей = РегистрыСведений.ПотокиОбновления.СоздатьНаборЗаписей();
НаборЗаписей.Записать();
КонецПроцедуры
// Контекст выполнения обработчика обновления.
//
// Возвращаемое значение:
// Структура - описание контекста (сериализуется для возможности передачи в фоновое задание):
// * ВыполнитьОбработчик - Булево - если Истина, то обработчик готов к выполнению.
// * ДетальноеОписаниеОбработчика - см. ПодготовитьДетальнуюИнформациюОХодеОбновления
// * ЗавершениеПроцедурыОбработчика - Число - завершение процедуры обработки данных.
// * ЗаписыватьВЖурнал - Булево - см. Константы.ДетализироватьОбновлениеИБВЖурналеРегистрации.
// * ЗапускВыполненБезОшибок - Булево - если Истина, то при запуске обработчика не возникло исключений.
// * ИдентификаторОбработчика - УникальныйИдентификатор - идентификатор обработчика обновления.
// * ИмяОбработчика - Строка - имя обработчика обновления.
// * ИндексОписанияЦиклаОбновления - Число - индекс элемента плана обновления.
// * ИндексТекущегоЦиклаОбновления - Число - индекс текущего элемента плана обновления.
// * НачалоОбработкиДанных - Дата - время начала выполнения обработчика обновления.
// * НачалоПроцедурыОбработчика - Число - начало процедуры обработки данных.
// * ПереданоДанныхДляОбработки - Число - количество объектов, переданных для обработки.
// * ПараллельныйРежим - Булево - признак параллельного режима выполнения обработчика обновления.
// * Параметры - Структура - параметры обработчика обновления со свойствами:
// ** ОбновляемыеДанные - см. НоваяПорцияДляОбновления
// * ПараметрыОбновления - Структура - описание параметров обновления.
// * ПараметрыОбработчикаОбновления - см. ПараметрыСеанса.ПараметрыОбработчикаОбновления
// * ПропуститьПроверкуОбработанныхДанных - Булево - пропустить проверку в подчиненном узле РИБ.
// * ТекущаяИтерацияОбновления - Число - номер текущей итерации обновления.
// * ТранзакцияАктивнаНаНачалоВыполнения - Булево - состояние активности транзакции перед выполнением обработчика.
// * ВерсияПодсистемыНаНачалоОбновления - Строка - версия подсистемы, к которой относится обработчик обновления,
// на момент начала обновления.
//
Функция НовыйКонтекстОбработчика()
КонтекстОбработчика = Новый Структура;
КонтекстОбработчика.Вставить("ВыполнитьОбработчик", Ложь);
КонтекстОбработчика.Вставить("ДетальноеОписаниеОбработчика");
КонтекстОбработчика.Вставить("ЕстьНеЗакрытыеТранзакции", Ложь);
КонтекстОбработчика.Вставить("ЗавершениеПроцедурыОбработчика");
КонтекстОбработчика.Вставить("ЗаписыватьВЖурнал");
КонтекстОбработчика.Вставить("ЗапускВыполненБезОшибок", Ложь);
КонтекстОбработчика.Вставить("ИдентификаторОбработчика");
КонтекстОбработчика.Вставить("ИмяОбработчика");
КонтекстОбработчика.Вставить("ИндексОписанияЦиклаОбновления");
КонтекстОбработчика.Вставить("ИндексТекущегоЦиклаОбновления");
КонтекстОбработчика.Вставить("ИнформацияОбОшибке");
КонтекстОбработчика.Вставить("НачалоОбработкиДанных");
КонтекстОбработчика.Вставить("НачалоПроцедурыОбработчика");
КонтекстОбработчика.Вставить("ПереданоДанныхДляОбработки");
КонтекстОбработчика.Вставить("ПараллельныйРежим");
КонтекстОбработчика.Вставить("Параметры");
КонтекстОбработчика.Вставить("ПараметрыОбновления");
КонтекстОбработчика.Вставить("ПараметрыОбработчикаОбновления");
КонтекстОбработчика.Вставить("ПропуститьПроверкуОбработанныхДанных", Ложь);
КонтекстОбработчика.Вставить("ТекущаяИтерацияОбновления");
КонтекстОбработчика.Вставить("ТранзакцияАктивнаНаНачалоВыполнения");
КонтекстОбработчика.Вставить("ВерсияПодсистемыНаНачалоОбновления");
Возврат КонтекстОбработчика;
КонецФункции
// Дополнить контекст обработчика полями для многопоточного обработчика.
//
// Параметры:
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
//
Процедура ДополнитьКонтекстМногопоточногоОбработчика(КонтекстОбработчика)
КонтекстОбработчика.Параметры.Вставить("ОбновляемыеДанные");
КонецПроцедуры
// Результат выполнения отложенного обработчика обновления для передачи в процедуру завершения
// его выполнения в управляющем потоке.
//
// Возвращаемое значение:
// Структура:
// * ЕстьНеЗакрытыеТранзакции - Булево - признак наличия не закрытых транзакций в самом обработчике.
// * ЗавершениеПроцедурыОбработчика - Число - время завершения выполнения процедуры обработчика обновления.
// * ИнформацияОбОшибке - Строка - описание ошибки (если была).
// * НачалоПроцедурыОбработчика - Число - время начала выполнения процедуры обработчика обновления.
// * ПереданоДанныхДляОбработки - Число - количество объектов, переданных для обработки.
// * Параметры - Структура - параметры, переданные в обработчик обновления.
// * ПараметрыОбработчикаОбновления - ФиксированнаяСтруктура - значение параметра сеанса
// ПараметрыОбработчикаОбновления.
//
Функция НовыйРезультатВыполненияОтложенногоОбработчика()
Результат = Новый Структура;
Результат.Вставить("ЕстьНеЗакрытыеТранзакции", Ложь);
Результат.Вставить("ЗавершениеПроцедурыОбработчика");
Результат.Вставить("ИнформацияОбОшибке");
Результат.Вставить("НачалоПроцедурыОбработчика");
Результат.Вставить("ПереданоДанныхДляОбработки");
Результат.Вставить("Параметры");
Результат.Вставить("ПараметрыОбработчикаОбновления");
Возврат Результат;
КонецФункции
// Количество потоков обновления по умолчанию.
//
// Возвращаемое значение:
// Число - количество потоков равное 1 (для обратной совместимости), если не переопределено в
// ОбновлениеИнформационнойБазыПереопределяемый.ПриОпределенииНастроек().
//
Функция КоличествоПотоковОбновленияИнформационнойБазыПоУмолчанию()
Параметры = НастройкиПодсистемы();
Возврат Параметры.КоличествоПотоковОбновленияИнформационнойБазыПоУмолчанию;
КонецФункции
// Определить приоритет обновления.
//
// Параметры:
// СведенияОбОбновлении - см. СведенияОбОбновленииИнформационнойБазы
//
// Возвращаемое значение:
// Булево - Истина - приоритет на обработку данных, Ложь - приоритет на работу пользователей.
//
Функция ФорсироватьОбновление(СведенияОбОбновлении)
Если Не ОбщегоНазначения.РазделениеВключено() Тогда
ПараметрЗапускаКлиента = ПараметрыСеанса.ПараметрыКлиентаНаСервере.Получить("ПараметрЗапуска");
Если СтрНайти(НРег(ПараметрЗапускаКлиента), НРег("ФорсироватьОтложенноеОбновление")) > 0 Тогда
Возврат Истина;
Иначе
Возврат СведенияОбОбновлении.УправлениеОтложеннымОбновлением.Свойство("ФорсироватьОбновление");
КонецЕсли;
Иначе
Приоритет = Неопределено;
ИнтеграцияПодсистемБСП.ПриПолученииПриоритетаОбновления(Приоритет);
Если Приоритет = "РаботаПользователей" Тогда
Возврат Ложь;
ИначеЕсли Приоритет = "ОбработкаДанных" Тогда
Возврат Истина;
Иначе
Возврат СведенияОбОбновлении.УправлениеОтложеннымОбновлением.Свойство("ФорсироватьОбновление");
КонецЕсли;
КонецЕсли;
КонецФункции
////////////////////////////////////////////////////////////////////////////////
// Механизм работы с потоками.
Процедура СохранитьПотокОбновления(Поток)
НаборЗаписей = РегистрыСведений.ПотокиОбновления.СоздатьНаборЗаписей();
Идентификатор = Поток.ИдентификаторПотока;
Если Не ЗначениеЗаполнено(Идентификатор) Тогда
Идентификатор = Новый УникальныйИдентификатор;
КонецЕсли;
НаборЗаписей.Отбор.ИдентификаторПотока.Установить(Идентификатор);
НаборЗаписей.Прочитать();
Если НаборЗаписей.Количество() = 0 Тогда
Запись = НаборЗаписей.Добавить();
Иначе
Запись = НаборЗаписей[0];
КонецЕсли;
ЗаполнитьЗначенияСвойств(Запись, Поток, , "ИдентификаторПотока,ПараметрыПроцедуры,ПараметрыПроцедурыЗавершения");
Запись.ИдентификаторПотока = Идентификатор;
Запись.ПараметрыПроцедуры = Новый ХранилищеЗначения(Поток.ПараметрыПроцедуры);
Запись.ПараметрыПроцедурыЗавершения = Новый ХранилищеЗначения(Поток.ПараметрыПроцедурыЗавершения);
НаборЗаписей.Записать();
КонецПроцедуры
Процедура УдалитьПотокОбновления(ИдентификаторПотока)
НаборЗаписей = РегистрыСведений.ПотокиОбновления.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ИдентификаторПотока.Установить(ИдентификаторПотока);
НаборЗаписей.Записать();
КонецПроцедуры
Функция ПотокиОбновления()
ТаблицаПотоков = НовоеОписаниеПотоков();
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПотокиОбновления.АдресРезультата КАК АдресРезультата,
| ПотокиОбновления.Группа КАК Группа,
| ПотокиОбновления.Наименование КАК Наименование,
| ПотокиОбновления.ПараметрыПроцедуры КАК ПараметрыПроцедуры,
| ПотокиОбновления.ПараметрыПроцедурыЗавершения КАК ПараметрыПроцедурыЗавершения,
| ПотокиОбновления.ПриоритетЗавершения КАК ПриоритетЗавершения,
| ПотокиОбновления.ИдентификаторЗадания КАК ИдентификаторЗадания,
| ПотокиОбновления.ИдентификаторПотока КАК ИдентификаторПотока
|ИЗ
| РегистрСведений.ПотокиОбновления КАК ПотокиОбновления";
Результат = Запрос.Выполнить().Выгрузить();
Для Каждого Поток Из Результат Цикл
Строка = ТаблицаПотоков.Добавить();
ЗаполнитьЗначенияСвойств(Строка, Поток, , "ПараметрыПроцедуры,ПараметрыПроцедурыЗавершения");
Если Не ЗначениеЗаполнено(Строка.АдресРезультата) Тогда
Строка.АдресРезультата = Неопределено;
КонецЕсли;
Строка.ПараметрыПроцедурыЗавершения = Поток.ПараметрыПроцедурыЗавершения.Получить();
Строка.ПараметрыПроцедуры = Поток.ПараметрыПроцедуры.Получить();
КонецЦикла;
Возврат ТаблицаПотоков;
КонецФункции
// Выполнить указанный поток.
//
// Параметры:
// Группы - Соответствие
// Поток - СтрокаТаблицыЗначений - описание потока, см. Потоки в НовоеОписаниеПотоков.
// ИдентификаторФормы - УникальныйИдентификатор - идентификатор формы, если есть.
//
Процедура ВыполнитьПоток(Группы, Поток, ИдентификаторФормы = Неопределено)
ОписаниеПотока = Группы[Поток.Группа];
Если Не ПустаяСтрока(ОписаниеПотока.Процедура) И Поток.ПараметрыПроцедуры <> Неопределено Тогда
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(ИдентификаторФормы);
ПараметрыВыполнения.НаименованиеФоновогоЗадания = Поток.Наименование;
ПараметрыВыполнения.ОжидатьЗавершение = 0;
Если ИдентификаторФормы = Неопределено Тогда
ПараметрыВыполнения.АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено, Новый УникальныйИдентификатор);
КонецЕсли;
РезультатЗапуска = ДлительныеОперации.ВыполнитьВФоне(ОписаниеПотока.Процедура,
Поток.ПараметрыПроцедуры,
ПараметрыВыполнения);
Поток.АдресРезультата = РезультатЗапуска.АдресРезультата;
Статус = РезультатЗапуска.Статус;
Если Статус = "Выполняется" Тогда
Поток.ИдентификаторЗадания = РезультатЗапуска.ИдентификаторЗадания;
ИначеЕсли Статус <> "Выполняется" И Статус <> "Выполнено" Тогда
ВызватьИсключение РезультатЗапуска.КраткоеПредставлениеОшибки;
КонецЕсли;
КонецЕсли;
СохранитьПотокОбновления(Поток);
КонецПроцедуры
// Завершает выполнение потоков, которые завершили выполнение своих фоновых заданий.
//
// Параметры:
// Потоки - см. НовоеОписаниеПотоков
// Группы - Соответствие
//
// Возвращаемое значение:
// Булево - Истина, если завершился один или более потоков, иначе - Ложь.
//
Функция ЗавершитьПотокиВыполнившиеФЗ(Потоки, Группы)
ЕстьЗавершенныеПотоки = Ложь;
Потоки.Сортировать("ПриоритетЗавершения Убыв");
Индекс = Потоки.Количество() - 1;
Пока Индекс >= 0 Цикл
Поток = Потоки[Индекс];
ОписаниеПотока = Группы[Поток.Группа];
ИдентификаторЗадания = Поток.ИдентификаторЗадания;
Если ЗначениеЗаполнено(ИдентификаторЗадания) Тогда
Попытка
ЗаданиеВыполнено = ДлительныеОперации.ЗаданиеВыполнено(ИдентификаторЗадания);
Исключение
ИнформацияОбОшибке = ИнформацияОбОшибке();
ЗаданиеВыполнено = Неопределено;
Если Не ПустаяСтрока(ОписаниеПотока.ПриАварийномЗавершении) Тогда
ПараметрыВызова = Новый Массив;
ПараметрыВызова.Добавить(Поток);
ПараметрыВызова.Добавить(ИнформацияОбОшибке);
ОбщегоНазначения.ВыполнитьМетодКонфигурации(ОписаниеПотока.ПриАварийномЗавершении, ПараметрыВызова);
Иначе
ВызватьИсключение;
КонецЕсли;
КонецПопытки;
КонецЕсли;
Если Не ЗначениеЗаполнено(ИдентификаторЗадания) Или ЗаданиеВыполнено <> Ложь Тогда
Выполнять = Не ПустаяСтрока(ОписаниеПотока.ПроцедураЗавершения)
И Поток.ПараметрыПроцедурыЗавершения <> Неопределено
И (Не ЗначениеЗаполнено(ИдентификаторЗадания) Или ЗаданиеВыполнено = Истина)
И Поток.АдресРезультата <> Неопределено;
Если Выполнять Тогда
ПараметрыВызова = Новый Массив;
ПараметрыВызова.Добавить(Поток.ПараметрыПроцедурыЗавершения);
ПараметрыВызова.Добавить(Поток.АдресРезультата);
ОбщегоНазначения.ВыполнитьМетодКонфигурации(ОписаниеПотока.ПроцедураЗавершения, ПараметрыВызова);
КонецЕсли;
Если Поток.АдресРезультата <> Неопределено Тогда
УдалитьИзВременногоХранилища(Поток.АдресРезультата);
КонецЕсли;
УдалитьПотокОбновления(Поток.ИдентификаторПотока);
Потоки.Удалить(Поток);
ЕстьЗавершенныеПотоки = Истина;
КонецЕсли;
Индекс = Индекс - 1;
КонецЦикла;
Возврат ЕстьЗавершенныеПотоки;
КонецФункции
// Ожидать завершение всех потоков.
//
// Параметры:
// Группы - Соответствие
//
Процедура ОжидатьЗавершениеВсехПотоков(Группы)
Потоки = ПотокиОбновления();
Пока Потоки.Количество() > 0 Цикл
Если Не ЗавершитьПотокиВыполнившиеФЗ(Потоки, Группы) Тогда
ОжидатьЗавершениеПотока(Потоки[0]);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// Ожидать завершение любого потока.
//
// Параметры:
// Группы - Соответствие
//
Процедура ОжидатьЗавершениеЛюбогоПотока(Группы)
Потоки = ПотокиОбновления();
КоличествоПотоков = Потоки.Количество();
Пока КоличествоПотоков > 0 И Потоки.Количество() >= КоличествоПотоков Цикл
Если Не ЗавершитьПотокиВыполнившиеФЗ(Потоки, Группы) Тогда
ОжидатьЗавершениеПотока(Потоки[0]);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// Ожидать, пока количество выполняющихся потоков не станет меньше максимального.
//
// Параметры:
// Группы - Соответствие
//
Процедура ОжидатьСвободныйПоток(Группы)
МаксимумПотоков = КоличествоПотоковОбновленияИнформационнойБазы();
Потоки = ПотокиОбновления();
Пока Потоки.Количество() >= МаксимумПотоков Цикл
Если ЗавершитьПотокиВыполнившиеФЗ(Потоки, Группы) Тогда
Продолжить;
КонецЕсли;
ОжидатьЗавершениеПотока(Потоки[0]);
МаксимумПотоков = КоличествоПотоковОбновленияИнформационнойБазы();
КонецЦикла;
КонецПроцедуры
// Отменить выполнение потоков, если они активны.
//
// Параметры:
// Группы - Соответствие
//
Процедура ОтменитьВыполнениеВсехПотоков(Группы) Экспорт
Потоки = ПотокиОбновления();
Для Каждого Поток Из Потоки Цикл
ОписаниеПотока = Группы[Поток.Группа];
Если ЗначениеЗаполнено(Поток.ИдентификаторЗадания) Тогда
ДлительныеОперации.ОтменитьВыполнениеЗадания(Поток.ИдентификаторЗадания);
КонецЕсли;
Если ОписаниеПотока.ПриОтменеПотока <> Неопределено Тогда
ПараметрыВызова = Новый Массив;
ПараметрыВызова.Добавить(Поток);
ОбщегоНазначения.ВыполнитьМетодКонфигурации(ОписаниеПотока.ПриОтменеПотока, ПараметрыВызова);
КонецЕсли;
УдалитьПотокОбновления(Поток.ИдентификаторПотока);
КонецЦикла;
КонецПроцедуры
// Описание группы потоков.
//
// Возвращаемое значение:
// Структура - общее описание потоков со следующими полями:
// * Процедура - Строка - имя процедуры, выполняемой в фоновом задании. Объявление:
// ИмяПроцедуры(ОписаниеПроцедуры, АдресРезультата), где:
// ОписаниеПроцедуры - Структура - описание процедуры заполнения.
// АдресРезультата - Строка - адрес временного хранилища для сохранения результата выполнения.
// * ПроцедураЗавершения - Строка - имя процедуры, выполняемой, после завершения работы фонового задания. Объявление:
// ПроцедураЗавершения(ОписаниеПроцедуры, АдресРезультата, ДополнительныеПараметры), где:
// ОписаниеПроцедуры - Структура - описание процедуры заполнения.
// АдресРезультата - Строка - адрес временного хранилища с результатом выполнения.
// ДополнительныеПараметры - Произвольный - дополнительный параметр.
// * ПриАварийномЗавершении - Строка - обработчик аварийного завершения потока. Объявление:
// ПриАварийномЗавершении(Поток, ИнформацияОбОшибке, ДополнительныеПараметры), где:
// Поток - см. НовоеОписаниеПотоков
// ИнформацияОбОшибке - ИнформацияОбОшибке - описание возникшей ошибки.
// ДополнительныеПараметры - Произвольный - дополнительный параметр.
// * ПриОтменеПотока - Строка - обработчик отмены потока. Объявление:
// ПриОтменеПотока(Поток, ДополнительныеПараметры), где:
// Поток - см. НовоеОписаниеПотоков
// ДополнительныеПараметры - Произвольный - дополнительный параметр.
//
Функция НовоеОписаниеГруппыПотоков()
Описание = Новый Структура;
Описание.Вставить("Процедура");
Описание.Вставить("ПроцедураЗавершения");
Описание.Вставить("ПриАварийномЗавершении");
Описание.Вставить("ПриОтменеПотока");
Возврат Описание;
КонецФункции
// Описание группы потоков.
//
// Возвращаемое значение:
// Структура:
// * Группы - Соответствие из КлючИЗначение - описание групп потоков, где:
// ** Ключ - Строка - имя группы.
// ** Значение - см. НовоеОписаниеГруппыПотоков
// * Потоки - ТаблицаЗначений - описание потоков со следующими колонками:
// ** Наименование - Строка - произвольное наименование потока (используется в наименовании фонового задания).
// ** Группа - Строка - имя группы с описанием потока.
// ** ИдентификаторЗадания - УникальныйИдентификатор - уникальный идентификатор фонового задания.
// ** ПараметрыПроцедуры - Произвольный - параметры для Процедура.
// ** ПараметрыПроцедурыЗавершения - Произвольный - параметры для ПроцедураЗавершения.
// ** АдресРезультата - Строка - адрес временного хранилища для сохранения результата выполнения фонового задания.
//
Функция НовоеОписаниеПотоков()
Потоки = Новый ТаблицаЗначений;
Колонки = Потоки.Колонки;
Колонки.Добавить("Наименование");
Колонки.Добавить("Группа");
Колонки.Добавить("ПриоритетЗавершения", Новый ОписаниеТипов("Число"));
Колонки.Добавить("ИдентификаторЗадания");
Колонки.Добавить("ИдентификаторПотока");
Колонки.Добавить("ПараметрыПроцедуры");
Колонки.Добавить("ПараметрыПроцедурыЗавершения");
Колонки.Добавить("АдресРезультата");
Возврат Потоки;
КонецФункции
// Ожидать завершение потока в течение указанной длительности.
//
// Параметры:
// Поток - СтрокаТаблицыЗначений - поток, завершение которого необходимо ожидать.
// Длительность - Число - максимальная длительность ожидания в секундах.
//
// Возвращаемое значение:
// Булево - Истина - поток выполнен, Ложь - поток еще выполняется.
//
Функция ОжидатьЗавершениеПотока(Поток, Длительность = 1)
Если ЗначениеЗаполнено(Поток.ИдентификаторЗадания) Тогда
Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(Поток.ИдентификаторЗадания);
Если Задание <> Неопределено Тогда
Задание = Задание.ОжидатьЗавершенияВыполнения(Длительность);
ЗаданиеЗавершено = (Задание.Состояние <> СостояниеФоновогоЗадания.Активно);
Возврат ЗаданиеЗавершено;
КонецЕсли;
КонецЕсли;
Возврат Истина;
КонецФункции
////////////////////////////////////////////////////////////////////////////////
// Механизм многопоточного выполнения обработчика обновления.
// Найти порцию данных для потока обработчика обновления.
//
// Параметры:
// ПараметрыПоиска - см. НовыеПараметрыПоискаПорции
// АдресРезультата - Строка - адрес результата выполнения процедуры. Возвращается таблица значений.
//
Процедура НайтиПорциюДляОбновления(ПараметрыПоиска, АдресРезультата) Экспорт
ПараметрыВыборки = ПараметрыПоиска.ПараметрыВыборки;
ПроверитьПараметрыВыборки(ПараметрыВыборки);
ПараметрыВыборки.МаксимумВыборки = ОбновлениеИнформационнойБазы.МаксимальноеКоличествоЗаписейВВыборке();
ПоляУпорядочивания = ПоляУпорядочиванияПриПоискеПорций(ПараметрыПоиска);
ПараметрыВыборки.ПоляУпорядочивания = ПоляУпорядочивания;
ПараметрыВыборки.ОптимизироватьВыборкуПоСтраницам = Не ЕстьУпорядочиваниеПоВнешнимТаблицам(ПоляУпорядочивания);
Максимум = ОбновлениеИнформационнойБазы.МаксимальноеКоличествоЗаписейВВыборке();
ПараметрыОбхода = ПараметрыОбходаДанныхДляОбновления(ПараметрыПоиска);
ИтераторОбхода = ТекущиеПараметрыОбхода(ПараметрыОбхода);
РезультатПоиска = НовыйРезультатПоискаПорции();
НаборДанных = НовыйНаборДанныхДляОбновления();
РезультатПоиска.НаборДанных = НаборДанных;
ПараметрыВыборки = ПараметрыПоиска.ПараметрыВыборки;
ДополнительныеИсточникиДанных = ПараметрыВыборки.ДополнительныеИсточникиДанных;
Очередь = ПараметрыПоиска.Очередь;
Пока ИтераторОбхода <> Неопределено Цикл
СсылочныйОбъект = ИтераторОбхода.СсылочныйОбъект;
ТабличныйОбъект = ИтераторОбхода.ТабличныйОбъект;
УстановитьГраницуНачалаВыборки(ПараметрыПоиска, ИтераторОбхода.СсылочныйИндекс, ИтераторОбхода.ТабличныйИндекс);
УстановитьГраницуКонцаВыборки(ПараметрыПоиска, СсылочныйОбъект, ТабличныйОбъект);
МаксимумВыборки = ПараметрыВыборки.МаксимумВыборки;
ПараметрыВыборки.ДополнительныеИсточникиДанных = ОбновлениеИнформационнойБазы.ИсточникиДанных(
ДополнительныеИсточникиДанных,
СсылочныйОбъект,
ТабличныйОбъект);
Данные = ВыбратьДанныеПорции(ПараметрыВыборки, Очередь, СсылочныйОбъект, ТабличныйОбъект);
Количество = Данные.Количество();
РезультатПоиска.Количество = РезультатПоиска.Количество + Количество;
ПараметрыВыборки.МаксимумВыборки = ПараметрыВыборки.МаксимумВыборки - Количество;
Если Количество > 0 Тогда
ЗаписьНабора = НаборДанных.Добавить();
ЗаписьНабора.СсылочныйОбъект = СсылочныйОбъект;
ЗаписьНабора.ТабличныйОбъект = ТабличныйОбъект;
ЗаписьНабора.Данные = Данные;
КонецЕсли;
Если РезультатПоиска.Количество < Максимум Тогда
СледующиеПараметрыОбхода(ПараметрыОбхода, Количество = МаксимумВыборки);
ИтераторОбхода = ТекущиеПараметрыОбхода(ПараметрыОбхода);
Иначе
Прервать;
КонецЕсли;
КонецЦикла;
ПараметрыВыборки.ДополнительныеИсточникиДанных = ДополнительныеИсточникиДанных;
РезультатПоиска.ПоискЗавершен = (ИтераторОбхода = Неопределено);
ПоместитьВоВременноеХранилище(РезультатПоиска, АдресРезультата);
КонецПроцедуры
// Проверить корректность заполнения параметров выборки данных обработчика обновления.
//
// Параметры:
// ПараметрыВыборки - см. ОбновлениеИнформационнойБазы.ДополнительныеПараметрыВыборкиДанныхДляМногопоточнойОбработки
//
Процедура ПроверитьПараметрыВыборки(ПараметрыВыборки)
СпособВыборки = ПараметрыВыборки.СпособВыборки;
ИзвестныйСпособ = (СпособВыборки = ОбновлениеИнформационнойБазы.СпособВыборкиИзмеренияНезависимогоРегистраСведений())
Или (СпособВыборки = ОбновлениеИнформационнойБазы.СпособВыборкиРегистраторыРегистра())
Или (СпособВыборки = ОбновлениеИнформационнойБазы.СпособВыборкиСсылки());
Если Не ИзвестныйСпособ Тогда
ШаблонСообщения = НСтр(
"ru = 'Укажите способ выборки в процедуре регистрации данных к обновлению.
|Указывается в ""%1"".
|Сейчас указан неизвестный способ выборки ""%2"".'");
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, СпособВыборки, "Параметры.ПараметрыВыборки.СпособВыборки");
КонецЕсли;
ТаблицыУказаны = Не ПустаяСтрока(ПараметрыВыборки.ПолныеИменаОбъектов)
Или Не ПустаяСтрока(ПараметрыВыборки.ПолныеИменаРегистров);
Если Не ТаблицыУказаны Тогда
ШаблонСообщения = НСтр(
"ru = 'Укажите обрабатываемые таблицы в процедуре регистрации данных к обновлению.
|Указывается в ""%1"" и/или
|""%2"".'");
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения,
"Параметры.ПараметрыВыборки.ПолныеИменаОбъектов", "Параметры.ПараметрыВыборки.ПолныеИменаРегистров");
КонецЕсли;
КонецПроцедуры
// Установить границу начала выборки порции.
//
// Параметры:
// ПараметрыПоиска - см. НовыеПараметрыПоискаПорции
// СсылочныйИндекс - Число - номер итерации по ссылочным объектам.
// ТабличныйИндекс - Число - номер итерации по табличным объектам.
//
Процедура УстановитьГраницуНачалаВыборки(ПараметрыПоиска, СсылочныйИндекс, ТабличныйИндекс)
ПараметрыВыборки = ПараметрыПоиска.ПараметрыВыборки;
ПоследняяВыбраннаяЗапись = ПараметрыПоиска.ПоследняяВыбраннаяЗапись;
ПерваяЗапись = ПараметрыПоиска.ПерваяЗапись;
Если СсылочныйИндекс = 0 И ТабличныйИндекс = 0 Тогда // Выбирается первая страница в цикле выборки.
ПараметрыВыборки.ПоследняяВыбраннаяЗапись = ПоследняяВыбраннаяЗапись;
ПараметрыВыборки.ПерваяЗапись = ПерваяЗапись;
Иначе // Выбираются последующие страницы в цикле выборки (всегда в новом объекте, поэтому сначала).
ПараметрыВыборки.ПоследняяВыбраннаяЗапись = Неопределено;
ПараметрыВыборки.ПерваяЗапись = Неопределено;
КонецЕсли;
КонецПроцедуры
// Установить границу конца выборки порции.
//
// Параметры:
// ПараметрыПоиска - см. НовыеПараметрыПоискаПорции
// СсылочныйОбъект - Строка - полное имя ссылочного объекта метаданных.
// ТабличныйОбъект - Строка - полное имя табличного объекта метаданных.
//
Процедура УстановитьГраницуКонцаВыборки(ПараметрыПоиска, СсылочныйОбъект, ТабличныйОбъект)
ПараметрыВыборки = ПараметрыПоиска.ПараметрыВыборки;
ПоследняяЗапись = ПараметрыПоиска.ПоследняяЗапись;
ЭтоПоследнийОбъект = ПоследняяЗапись <> Неопределено
И СсылочныйОбъект = ПоследняяЗапись[0].Значение
И ТабличныйОбъект = ПоследняяЗапись[1].Значение;
Если ЭтоПоследнийОбъект Тогда // Последний объект в цикле обхода метаданных (конец выборки).
ПараметрыВыборки.ПоследняяЗапись = ПоследняяЗапись;
Иначе // Промежуточная выборка.
ПараметрыВыборки.ПоследняяЗапись = Неопределено;
КонецЕсли;
КонецПроцедуры
// Выбрать данные порции указанным способом.
//
// Параметры:
// ПараметрыВыборки - см. ОбновлениеИнформационнойБазы.ДополнительныеПараметрыВыборкиДанныхДляМногопоточнойОбработки
// Очередь - Число - номер очереди.
// СсылочныйОбъект - Строка - полное имя ссылочного объекта метаданных.
// ТабличныйОбъект - Строка - полное имя табличного объекта метаданных.
//
// Возвращаемое значение:
// ТаблицаЗначений - данные порции.
//
Функция ВыбратьДанныеПорции(ПараметрыВыборки, Очередь, СсылочныйОбъект, ТабличныйОбъект)
СпособВыборки = ПараметрыВыборки.СпособВыборки;
Если СпособВыборки = ОбновлениеИнформационнойБазы.СпособВыборкиИзмеренияНезависимогоРегистраСведений() Тогда
Данные = ОбновлениеИнформационнойБазы.ВыбратьИзмеренияНезависимогоРегистраСведенийДляОбработки(
Очередь,
ТабличныйОбъект,
ПараметрыВыборки);
ИначеЕсли СпособВыборки = ОбновлениеИнформационнойБазы.СпособВыборкиРегистраторыРегистра() Тогда
Данные = ОбновлениеИнформационнойБазы.ВыбратьРегистраторыРегистраДляОбработки(
Очередь,
?(ПустаяСтрока(СсылочныйОбъект), Неопределено, СсылочныйОбъект),
ТабличныйОбъект,
ПараметрыВыборки);
ИначеЕсли СпособВыборки = ОбновлениеИнформационнойБазы.СпособВыборкиСсылки() Тогда
Данные = ОбновлениеИнформационнойБазы.ВыбратьСсылкиДляОбработки(
Очередь,
СсылочныйОбъект,
ПараметрыВыборки);
КонецЕсли;
Возврат Данные;
КонецФункции
// Подготовить параметры обхода данных для обновления.
// По сути найти границу начала выборки (то место, где остановились в последний раз).
//
// Параметры:
// ПараметрыПоиска - см. НовыеПараметрыПоискаПорции
//
// Возвращаемое значение:
// Структура - параметры поиска, со следующими полями:
// СсылочныеОбъекты - Массив - имена ссылочных объектов метаданных.
// ТабличныеОбъектыВсе - Массив - имена табличных объектов метаданных.
// ТабличныеОбъектыНачало - Массив - имена табличных объектов метаданных на первой итерации.
//
Функция ПараметрыОбходаДанныхДляОбновления(ПараметрыПоиска)
ПоследняяВыбраннаяЗапись = ПараметрыПоиска.ПоследняяВыбраннаяЗапись;
ПерваяЗапись = ПараметрыПоиска.ПерваяЗапись;
ПараметрыВыборки = ПараметрыПоиска.ПараметрыВыборки;
ПолныеИменаОбъектов = ПараметрыВыборки.ПолныеИменаОбъектов;
ПолныеИменаРегистров = ПараметрыВыборки.ПолныеИменаРегистров;
ПолныеИменаРегистровНачало = ПолныеИменаРегистров;
Если ПоследняяВыбраннаяЗапись <> Неопределено Тогда // Продолжение выборки по страницам.
ПерваяСсылочная = ПоследняяВыбраннаяЗапись[0].Значение;
ПерваяТабличная = ПоследняяВыбраннаяЗапись[1].Значение;
ИначеЕсли ПерваяЗапись <> Неопределено Тогда // Повтор выборки (завершившейся аварийно).
ПерваяСсылочная = ПерваяЗапись[0].Значение;
ПерваяТабличная = ПерваяЗапись[1].Значение;
Иначе // Начало выборки (выборка первой страницы).
ПерваяСсылочная = Неопределено;
ПерваяТабличная = Неопределено;
КонецЕсли;
Если Не ПустаяСтрока(ПолныеИменаОбъектов) И Не ПустаяСтрока(ПерваяСсылочная) Тогда // Есть ссылочные объекты.
// Установить ссылочную часть начала выборки на место, на котором она остановилась в последний раз.
ПолныеИменаОбъектовМассив = ОстатокМассива(ПолныеИменаОбъектов, ПерваяСсылочная);
Иначе
ПолныеИменаОбъектовМассив = СтрРазделитьСокрЛП(ПолныеИменаОбъектов, ",");
КонецЕсли;
Если Не ПустаяСтрока(ПолныеИменаРегистровНачало) И Не ПустаяСтрока(ПерваяТабличная) Тогда // Есть табличные объекты.
// Установить табличную часть начала выборки на место, на котором она остановилась в последний раз.
ПолныеИменаРегистровНачалоМассив = ОстатокМассива(ПолныеИменаРегистровНачало, ПерваяТабличная);
Иначе
ПолныеИменаРегистровНачалоМассив = СтрРазделитьСокрЛП(ПолныеИменаРегистровНачало, ",");
КонецЕсли;
Результат = Новый Структура;
Результат.Вставить("СсылочныеОбъекты", ПолныеИменаОбъектовМассив);
Результат.Вставить("ТабличныеОбъектыВсе", СтрРазделитьСокрЛП(ПолныеИменаРегистров, ","));
Результат.Вставить("ТабличныеОбъектыНачало", ПолныеИменаРегистровНачалоМассив);
Результат.Вставить("СсылочныйИндекс", 0);
Результат.Вставить("ТабличныйИндекс", 0);
Возврат Результат;
КонецФункции
// Получить следующую порцию параметров обхода данных для обновления.
//
// Параметры:
// ПараметрыОбхода - см. ПараметрыОбходаДанныхДляОбновления
//
// Возвращаемое значение:
// Структура - параметры обхода текущей итерации в виде структуры со следующими полями:
// * СсылочныйОбъект - Строка - имя ссылочного объекта.
// * ТабличныйОбъект - Строка - имя табличного объекта.
// Неопределено - если обход закончен.
//
Функция ТекущиеПараметрыОбхода(ПараметрыОбхода)
Если ПараметрыОбхода.СсылочныйИндекс < ПараметрыОбхода.СсылочныеОбъекты.Количество() Тогда
Если ПараметрыОбхода.СсылочныйИндекс = 0 Тогда
ТабличныеОбъекты = ПараметрыОбхода.ТабличныеОбъектыНачало;
Иначе
ТабличныеОбъекты = ПараметрыОбхода.ТабличныеОбъектыВсе;
КонецЕсли;
Если ПараметрыОбхода.ТабличныйИндекс < ТабличныеОбъекты.Количество() Тогда
СсылочныйОбъект = ПараметрыОбхода.СсылочныеОбъекты[ПараметрыОбхода.СсылочныйИндекс];
ТабличныйОбъект = ТабличныеОбъекты[ПараметрыОбхода.ТабличныйИндекс];
Результат = Новый Структура;
Результат.Вставить("СсылочныйОбъект", СсылочныйОбъект);
Результат.Вставить("ТабличныйОбъект", ТабличныйОбъект);
Результат.Вставить("СсылочныйИндекс", ПараметрыОбхода.СсылочныйИндекс);
Результат.Вставить("ТабличныйИндекс", ПараметрыОбхода.ТабличныйИндекс);
Возврат Результат;
КонецЕсли;
КонецЕсли;
Возврат Неопределено;
КонецФункции
// Перейти к следующим параметрам выборки, если не было выбрано ни одной записи с текущими параметрами.
//
// Параметры:
// ПараметрыОбхода - см. ПараметрыОбходаДанныхДляОбновления
// ПолнаяВыборка - Булево - Истина, если выбрано максимум записей.
//
Процедура СледующиеПараметрыОбхода(ПараметрыОбхода, ПолнаяВыборка)
Если Не ПолнаяВыборка Тогда
Если ПараметрыОбхода.СсылочныйИндекс = 0 Тогда
ТабличныеОбъекты = ПараметрыОбхода.ТабличныеОбъектыНачало;
Иначе
ТабличныеОбъекты = ПараметрыОбхода.ТабличныеОбъектыВсе;
КонецЕсли;
Если ПараметрыОбхода.ТабличныйИндекс = ТабличныеОбъекты.ВГраница() Тогда
ПараметрыОбхода.ТабличныйИндекс = 0;
ПараметрыОбхода.СсылочныйИндекс = ПараметрыОбхода.СсылочныйИндекс + 1;
Иначе
ПараметрыОбхода.ТабличныйИндекс = ПараметрыОбхода.ТабличныйИндекс + 1;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
// Получить поля упорядочивания для заданных параметров поиска порции.
//
// Параметры:
// ПараметрыПоиска - см. НовыеПараметрыПоискаПорции
//
// Возвращаемое значение:
// Строка - Массив - поля упорядочивания.
//
Функция ПоляУпорядочиванияПриПоискеПорций(ПараметрыПоиска)
ПараметрыВыборки = ПараметрыПоиска.ПараметрыВыборки;
Возврат ?(ПараметрыПоиска.ФорсироватьОбновление,
ПараметрыВыборки.ПоляУпорядочиванияПриОбработкеДанных,
ПараметрыВыборки.ПоляУпорядочиванияПриРаботеПользователей);
КонецФункции
// Определить, есть ли упорядочивание по полям присоединяемых таблиц.
//
// Параметры:
// ПоляУпорядочивания - Массив - поля упорядочивания.
//
// Возвращаемое значение:
// Булево - Истина, если есть упорядочивание по полям присоединяемых таблиц.
//
Функция ЕстьУпорядочиваниеПоВнешнимТаблицам(ПоляУпорядочивания)
Для каждого ПолеУпорядочивания Из ПоляУпорядочивания Цикл
Если СтрНайти(ПолеУпорядочивания, ".") > 0 Тогда
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
// Получить результат поиска, разбить его на порции и запустить потоки обновления.
//
// Параметры:
// ПараметрыПоиска - см. НовыеПараметрыПоискаПорции
// АдресРезультата - Строка - адрес результата выполнения НайтиПорциюДляОбновления
// СведенияОбОбновлении - см. СведенияОбОбновленииИнформационнойБазы
//
Процедура ЗавершитьПоискПорцииДляОбновления(ПараметрыПоиска, АдресРезультата) Экспорт
РезультатПоиска = ПолучитьИзВременногоХранилища(АдресРезультата);
Группы = НовоеОписаниеГруппПотоковОбработчиковОтложенногоОбновления();
КонтекстОбработчика = ПараметрыПоиска.КонтекстОбработчика;
ОбработчикОбновления = ОбработчикОбновления(КонтекстОбработчика.ИмяОбработчика);
ОписаниеПроцедурыЗаполнения = ОбработчикОбновления.ОбрабатываемыеДанные.Получить();
ПорцииДляОбновления = ОписаниеПроцедурыЗаполнения.ПорцииДляОбновления; // см. НоваяТаблицаПорцийДляОбновления
ИдентификаторПорции = ПараметрыПоиска.ИдентификаторПорции;
ЕстьИдентификатор = ИдентификаторПорции <> Неопределено;
СтараяПорция = ?(ЕстьИдентификатор, ПорцииДляОбновления.Найти(ИдентификаторПорции, "Идентификатор"), Неопределено);
ЭтоПервыйПоиск = ПараметрыПоиска.ПоследняяВыбраннаяЗапись = Неопределено
И ПараметрыПоиска.ПерваяЗапись = Неопределено
И ПараметрыПоиска.ПоследняяЗапись = Неопределено;
ЭтоПовторныйПоиск = ПараметрыПоиска.ПерваяЗапись <> Неопределено
И ПараметрыПоиска.ПоследняяЗапись <> Неопределено;
Если ЭтоПервыйПоиск Тогда
СохранитьРезультатПервогоПоиска(РезультатПоиска, ОписаниеПроцедурыЗаполнения);
ПорцииДляОбновления = ОписаниеПроцедурыЗаполнения.ПорцииДляОбновления;
ИначеЕсли ЭтоПовторныйПоиск Тогда
СохранитьРезультатПовторногоПоиска(РезультатПоиска, ОписаниеПроцедурыЗаполнения, ИдентификаторПорции);
Иначе
СохранитьРезультатПоиска(РезультатПоиска, ОписаниеПроцедурыЗаполнения);
КонецЕсли;
Если РезультатПоиска.Количество > 0 Тогда
МаксимумПотоков = КоличествоПотоковОбновленияИнформационнойБазы();
ПотокиОбновления = ПотокиОбновления();
СвободныхПотоков = МаксимумПотоков - ПотокиОбновления.Количество() + 1;
Если СвободныхПотоков = 0 Тогда
СвободныхПотоков = 1;
КонецЕсли;
Фрагменты = РазбитьРезультатПоискаНаФрагменты(РезультатПоиска, СвободныхПотоков);
КоличествоФрагментов = Фрагменты.Количество();
Для НомерФрагмента = 0 По КоличествоФрагментов - 1 Цикл
Фрагмент = Фрагменты[НомерФрагмента];
ЕстьСтараяПорция = (НомерФрагмента = 0 И СтараяПорция <> Неопределено);
Если ЕстьСтараяПорция Тогда
Порция = СтараяПорция;
Фрагмент.Идентификатор = Порция.Идентификатор;
Иначе
Порция = ПорцииДляОбновления.Добавить();
Порция.Идентификатор = Фрагмент.Идентификатор;
КонецЕсли;
Порция.ПерваяЗапись = Фрагмент.ПерваяЗапись;
Порция.ПоследняяЗапись = Фрагмент.ПоследняяЗапись;
Порция.Обрабатывается = Истина;
// Если порций больше одной, то для каждой свой КлючЗаписиПрогрессаОбновления прогресса обновления
ПараметрыОбработчикаОбновления = Новый Структура(КонтекстОбработчика.ПараметрыОбработчикаОбновления);
ПараметрыОбработчикаОбновления.КлючЗаписиПрогрессаОбновления = Новый УникальныйИдентификатор;
КонтекстОбработчика.ПараметрыОбработчикаОбновления = Новый ФиксированнаяСтруктура(ПараметрыОбработчикаОбновления);
ОбработатьФрагментДанныхВПотоке(Фрагмент, Группы, КонтекстОбработчика);
КонецЦикла;
Иначе
Фрагмент = НоваяПорцияДляОбновления();
Фрагмент.НаборДанных = НовыйНаборДанныхДляОбновления();
ОбработатьФрагментДанныхВПотоке(Фрагмент, Группы, КонтекстОбработчика);
КонецЕсли;
ОписаниеПроцедурыЗаполнения.ВыполняетсяПоискПорции = Ложь;
УстановитьСвойствоОбработчика(ОбработчикОбновления.ИмяОбработчика,
"ОбрабатываемыеДанные",
Новый ХранилищеЗначения(ОписаниеПроцедурыЗаполнения));
КонецПроцедуры
// Обработчик аварийного завершения выполнения потока поиска порции для обновления.
//
// Параметры:
// Поток - см. НовоеОписаниеПотоков
// ИнформацияОбОшибке - ИнформацияОбОшибке - описание возникшей ошибки.
// СведенияОбОбновлении - см. СведенияОбОбновленииИнформационнойБазы.
//
Процедура ПриАварийномЗавершенииПотокаПоискаПорцииДляОбновления(Поток, ИнформацияОбОшибке) Экспорт
ОбработчикОбновления = ОбработчикОбновления(Поток.ПараметрыПроцедуры.ИмяОбработчика);
Описание = ОбработчикОбновления.ОбрабатываемыеДанные.Получить();
Описание.ВыполняетсяПоискПорции = Ложь;
УстановитьСвойствоОбработчика(Поток.ПараметрыПроцедуры.ИмяОбработчика,
"ОбрабатываемыеДанные",
Новый ХранилищеЗначения(Описание));
КонецПроцедуры
// Обработчик отмены выполнения потока поиска порции для обновления.
//
// Параметры:
// Поток - см. НовоеОписаниеПотоков
// СведенияОбОбновлении - см. СведенияОбОбновленииИнформационнойБазы
//
Процедура ПриОтменеПотокаПоискаПорцииДляОбновления(Поток) Экспорт
ОбработчикОбновления = ОбработчикОбновления(Поток.ПараметрыПроцедуры.ИмяОбработчика);
Описание = ОбработчикОбновления.ОбрабатываемыеДанные.Получить();
Описание.ВыполняетсяПоискПорции = Ложь;
УстановитьСвойствоОбработчика(Поток.ПараметрыПроцедуры.ИмяОбработчика,
"ОбрабатываемыеДанные",
Новый ХранилищеЗначения(Описание));
КонецПроцедуры
// Завершить обработку данных многопоточного обработчика обновления.
// Удалить обработанную порцию данных.
//
// Параметры:
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
// СведенияОбОбновлении - см. СведенияОбОбновленииИнформационнойБазы
//
Процедура ЗавершитьВыполнениеМногопоточногоОбработчика(КонтекстОбработчика, ИмяОбработчика)
ОбработчикОбновления = ОбработчикОбновления(ИмяОбработчика);
ОписаниеПроцедурыЗаполнения = ОбработчикОбновления.ОбрабатываемыеДанные.Получить();
ПорцииДляОбновления = ОписаниеПроцедурыЗаполнения.ПорцииДляОбновления;
Если ПорцииДляОбновления <> Неопределено
И КонтекстОбработчика.Параметры.Свойство("ОбновляемыеДанные") Тогда
ОбновляемыеДанные = КонтекстОбработчика.Параметры.ОбновляемыеДанные;
Если ОбновляемыеДанные <> Неопределено Тогда
Порция = ПорцииДляОбновления.Найти(ОбновляемыеДанные.Идентификатор, "Идентификатор");
Если Порция <> Неопределено Тогда
ПорцииДляОбновления.Удалить(Порция);
КонецЕсли;
КонецЕсли;
КонецЕсли;
УстановитьСвойствоОбработчика(ОбработчикОбновления.ИмяОбработчика,
"ОбрабатываемыеДанные",
Новый ХранилищеЗначения(ОписаниеПроцедурыЗаполнения));
КонецПроцедуры
// Отменить обработку данных многопоточного обработчика обновления.
// Отметить, что найденную порцию данных нужно будет обрабатывать повторно.
//
// Параметры:
// Поток - СтрокаТаблицыЗначений:
// * Наименование - Строка - произвольное наименование потока (используется в наименовании фонового задания).
// * Группа - Строка - имя группы с описанием потока.
// * ИдентификаторЗадания - УникальныйИдентификатор - уникальный идентификатор фонового задания.
// * ПараметрыПроцедуры - см. НовыйКонтекстОбработчика
// * ПараметрыПроцедурыЗавершения - Произвольный - параметры для ПроцедураЗавершения.
// * АдресРезультата - Строка - адрес временного хранилища для сохранения результата выполнения фонового задания.
// ОбработчикОбновления - СтрокаДереваЗначений - обработчик обновления в виде строки дерева обработчиков.
// СведенияОбОбновлении - см. СведенияОбОбновленииИнформационнойБазы
//
Процедура ОтменитьОбработкуДанныхМногопоточногоОбработчика(Поток, ОбработчикОбновления)
ОписаниеПроцедурыЗаполнения = ОбработчикОбновления.ОбрабатываемыеДанные.Получить();
ПорцииДляОбновления = ОписаниеПроцедурыЗаполнения.ПорцииДляОбновления;
Если ПорцииДляОбновления <> Неопределено Тогда
ОбновляемыеДанные = Поток.ПараметрыПроцедуры.Параметры.ОбновляемыеДанные;
Если ОбновляемыеДанные <> Неопределено Тогда
Порция = ПорцииДляОбновления.Найти(ОбновляемыеДанные.Идентификатор, "Идентификатор");
Если Порция <> Неопределено Тогда
Порция.Обрабатывается = Ложь;
КонецЕсли;
КонецЕсли;
КонецЕсли;
УстановитьСвойствоОбработчика(ОбработчикОбновления.ИмяОбработчика,
"ОбрабатываемыеДанные",
Новый ХранилищеЗначения(ОписаниеПроцедурыЗаполнения));
КонецПроцедуры
// Сохранить результат первого поиска данных для многопоточного обработчика.
//
// Параметры:
// РезультатПоиска - см. НовыйРезультатПоискаПорции
// ОписаниеПроцедурыЗаполнения - см. НовоеОписаниеОбрабатываемыхДанных
//
Процедура СохранитьРезультатПервогоПоиска(РезультатПоиска, ОписаниеПроцедурыЗаполнения)
Если РезультатПоиска.Количество > 0 Тогда
ПоследняяВыбраннаяЗапись = КлючЗаписиПоследнейСтрокиНабораДанных(РезультатПоиска.НаборДанных);
ОписаниеПроцедурыЗаполнения.ПоследняяВыбраннаяЗапись = ПоследняяВыбраннаяЗапись;
Если ОписаниеПроцедурыЗаполнения.ПорцииДляОбновления = Неопределено Тогда
ОписаниеПроцедурыЗаполнения.ПорцииДляОбновления = НоваяТаблицаПорцийДляОбновления();
КонецЕсли;
Иначе
ОписаниеПроцедурыЗаполнения.ПоследняяВыбраннаяЗапись = Неопределено;
КонецЕсли;
ОписаниеПроцедурыЗаполнения.ПоискЗавершен = РезультатПоиска.ПоискЗавершен;
КонецПроцедуры
// Сохранить результат повторного (после ошибки) поиска данных для многопоточного обработчика.
//
// Параметры:
// РезультатПоиска - см. НовыйРезультатПоискаПорции
// ОписаниеПроцедурыЗаполнения - см. НовоеОписаниеОбрабатываемыхДанных
// ИдентификаторПорции - УникальныйИдентификатор - идентификатор порции для которой искались данные.
//
Процедура СохранитьРезультатПовторногоПоиска(РезультатПоиска, ОписаниеПроцедурыЗаполнения, ИдентификаторПорции)
Если РезультатПоиска.Количество = 0 Тогда
ПорцииДляОбновления = ОписаниеПроцедурыЗаполнения.ПорцииДляОбновления;
Порция = ПорцииДляОбновления.Найти(ИдентификаторПорции, "Идентификатор");
ПорцииДляОбновления.Удалить(Порция);
КонецЕсли;
ОписаниеПроцедурыЗаполнения.ПоискЗавершен = РезультатПоиска.ПоискЗавершен;
Если ОписаниеПроцедурыЗаполнения.Свойство("ИмяОбработчика") Тогда
УстановитьСвойствоОбработчика(ОписаниеПроцедурыЗаполнения.ИмяОбработчика,
"ОбрабатываемыеДанные",
Новый ХранилищеЗначения(ОписаниеПроцедурыЗаполнения));
КонецЕсли;
КонецПроцедуры
// Сохранить результат поиска данных для многопоточного обработчика.
//
// Параметры:
// РезультатПоиска - см. НовыйРезультатПоискаПорции
// ОписаниеПроцедурыЗаполнения - см. НовоеОписаниеОбрабатываемыхДанных
//
Процедура СохранитьРезультатПоиска(РезультатПоиска, ОписаниеПроцедурыЗаполнения)
Если РезультатПоиска.Количество > 0 Тогда
ПоследняяВыбраннаяЗапись = КлючЗаписиПоследнейСтрокиНабораДанных(РезультатПоиска.НаборДанных);
ОписаниеПроцедурыЗаполнения.ПоследняяВыбраннаяЗапись = ПоследняяВыбраннаяЗапись;
КонецЕсли;
ОписаниеПроцедурыЗаполнения.ПоискЗавершен = РезультатПоиска.ПоискЗавершен;
КонецПроцедуры
// Разбить найденные данные на указанное количество порций.
//
// Параметры:
// РезультатПоиска - см. НовыйРезультатПоискаПорции
// КоличествоФрагментов - Число - количество фрагментов на которые нужно разбить данные.
//
// Возвращаемое значение:
// см. НовыйНаборПорцийДляОбновления
//
Функция РазбитьРезультатПоискаНаФрагменты(РезультатПоиска, Знач КоличествоФрагментов)
Фрагменты = НовыйНаборПорцийДляОбновления();
НайденныйНаборДанных = РезультатПоиска.НаборДанных;
КоличествоНайденных = РезультатПоиска.Количество;
КоличествоФрагментов = ?(КоличествоНайденных < КоличествоФрагментов, 1, КоличествоФрагментов);
МаксимальныйРазмерПорции = Цел(КоличествоНайденных / КоличествоФрагментов);
КоличествоОбработанных = 0;
Для НомерФрагмента = 1 По КоличествоФрагментов Цикл // Разбивка идет с конца найденного набора данных.
Фрагмент = НоваяПорцияДляОбновления();
Фрагмент.Идентификатор = Новый УникальныйИдентификатор;
Фрагмент.НаборДанных = НовыйНаборДанныхДляОбновления();
Фрагмент.ПоследняяЗапись = КлючЗаписиПоследнейСтрокиНабораДанных(НайденныйНаборДанных);
Фрагменты.Вставить(0, Фрагмент);
ИндексНабораДанных = НайденныйНаборДанных.Количество() - 1;
КоличествоСвободных = ?(НомерФрагмента = КоличествоФрагментов,
КоличествоНайденных - КоличествоОбработанных,
МаксимальныйРазмерПорции);
Пока ИндексНабораДанных >= 0 Цикл
ТекущаяСтрокаДанных = НайденныйНаборДанных[ИндексНабораДанных];
ТекущиеДанные = ТекущаяСтрокаДанных.Данные;
ТекущееКоличество = ТекущиеДанные.Количество();
ДанныеФрагмента = Фрагмент.НаборДанных.Добавить();
Если ТекущееКоличество <= КоличествоСвободных Тогда
ЗаполнитьЗначенияСвойств(ДанныеФрагмента, ТекущаяСтрокаДанных);
НайденныйНаборДанных.Удалить(ИндексНабораДанных);
КоличествоСвободных = КоличествоСвободных - ТекущееКоличество;
КоличествоОбработанных = КоличествоОбработанных + ТекущееКоличество;
Иначе
ЗаполнитьЗначенияСвойств(ДанныеФрагмента, ТекущаяСтрокаДанных, "СсылочныйОбъект, ТабличныйОбъект");
НачалоВырезки = ТекущееКоличество - КоличествоСвободных;
ДанныеФрагмента.Данные = ВырезатьСтрокиИзТаблицыЗначений(ТекущиеДанные, НачалоВырезки, КоличествоСвободных);
КоличествоОбработанных = КоличествоОбработанных + КоличествоСвободных;
КоличествоСвободных = 0;
КонецЕсли;
Если КоличествоСвободных = 0 Тогда
Прервать;
Иначе
ИндексНабораДанных = ИндексНабораДанных - 1;
КонецЕсли;
КонецЦикла;
Фрагмент.ПерваяЗапись = КлючЗаписиПервойСтрокиНабораДанных(Фрагмент.НаборДанных);
КонецЦикла;
Возврат Фрагменты;
КонецФункции
// Вырезать СуществующиеПоставляемыеЭлементы таблицы значений в новую таблицу значений.
//
// Параметры:
// Таблица - ТаблицаЗначений - таблица из которой вырезаются строки.
// Начало - Число - индекс первой вырезаемой строки.
// Количество - Число - количество вырезаемых строк.
//
// Возвращаемое значение:
// ТаблицаЗначений - вырезанные строки в виде новой таблицы значений.
//
Функция ВырезатьСтрокиИзТаблицыЗначений(Таблица, Начало, Количество)
НоваяТаблица = Таблица.СкопироватьКолонки();
Индекс = Начало + Количество - 1;
Пока Индекс >= Начало Цикл
НоваяСтрока = НоваяТаблица.Добавить();
СтараяСтрока = Таблица[Индекс];
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтараяСтрока);
Таблица.Удалить(СтараяСтрока);
Индекс = Индекс - 1;
КонецЦикла;
Возврат НоваяТаблица;
КонецФункции
// Определяет, есть ли в обработчике порции, которые можно было бы обновить в новом потоке.
//
// Параметры:
// ОбработчикОбновления - СтрокаТаблицыЗначений - обработчик обновления в виде строки дерева обработчиков.
//
Функция ЕстьПорцииДляОбновления(ОбработчикОбновления)
Описание = ОбработчикОбновления.ОбрабатываемыеДанные.Получить();
Если Описание.ВыполняетсяПоискПорции Тогда
Возврат Ложь;
Иначе
Если Описание.ПорцииДляОбновления <> Неопределено И Описание.ПорцииДляОбновления.Количество() > 0 Тогда
Для каждого Порция Из Описание.ПорцииДляОбновления Цикл
Если Не Порция.Обрабатывается Тогда
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
Иначе
Возврат Истина;
КонецЕсли;
КонецЕсли;
КонецФункции
// Получить ключ записи первой строки набора данных.
//
// Параметры:
// НаборДанных - см. НовыйНаборДанныхДляОбновления
//
// Возвращаемое значение:
// СписокЗначений - ключ записи.
//
Функция КлючЗаписиПервойСтрокиНабораДанных(НаборДанных)
ПерваяСтрокаДанных = НаборДанных[0];
Возврат НовыйКлючЗаписиИзТаблицыДанных(ПерваяСтрокаДанных.СсылочныйОбъект,
ПерваяСтрокаДанных.ТабличныйОбъект,
ПерваяСтрокаДанных.Данные,
0);
КонецФункции
// Получить ключ записи последней строки набора данных.
//
// Параметры:
// НаборДанных - см. НовыйНаборДанныхДляОбновления
//
// Возвращаемое значение:
// СписокЗначений - ключ записи.
//
Функция КлючЗаписиПоследнейСтрокиНабораДанных(НаборДанных)
ПоследняяСтрокаДанных = НаборДанных[НаборДанных.Количество() - 1];
Возврат НовыйКлючЗаписиИзТаблицыДанных(ПоследняяСтрокаДанных.СсылочныйОбъект,
ПоследняяСтрокаДанных.ТабличныйОбъект,
ПоследняяСтрокаДанных.Данные,
ПоследняяСтрокаДанных.Данные.Количество() - 1);
КонецФункции
// Таблица с описанием порций обновляемых данных.
//
// Возвращаемое значение:
// ТаблицаЗначений:
// * Идентификатор - УникальныйИдентификатор - идентификатор порции.
// * ПерваяЗапись - СписокЗначений - первая запись в порции, где:
// ** Представление - Строка - имя поля.
// ** Значение - Произвольный - значение поля ключа.
// * ПоследняяЗапись - СписокЗначений - последняя запись в порции, где:
// ** Представление - Строка - имя поля.
// ** Значение - Произвольный - значение поля ключа.
// * Обрабатывается - Булево - Истина, если запущен поток обновления данных.
//
Функция НоваяТаблицаПорцийДляОбновления()
Таблица = Новый ТаблицаЗначений;
Колонки = Таблица.Колонки;
Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("УникальныйИдентификатор"));
Колонки.Добавить("ПерваяЗапись", Новый ОписаниеТипов("СписокЗначений"));
Колонки.Добавить("ПоследняяЗапись", Новый ОписаниеТипов("СписокЗначений"));
Колонки.Добавить("Обрабатывается", Новый ОписаниеТипов("Булево"));
Таблица.Индексы.Добавить("Идентификатор");
Возврат Таблица;
КонецФункции
// Описание обрабатываемых данных обработчика обновления (для СведенияОбОбновлении.ОбрабатываемыеДанные).
//
// Параметры:
// Многопоточное - Булево - Истина, если используется для многопоточного обработчика обновления.
// Фоновое - Булево - Истина, если используется для ЗаполнитьДанныеОтложенногоОбработчика().
//
// Возвращаемое значение:
// Структура - описание со следующими полями:
// * ДанныеОбработчика - Соответствие - данные регистрируемые и обрабатываемые обработчиком обновления.
// * ВыполняетсяПоискПорции - Булево - признак наличия потока, выполняющего поиск порции данных для обновления.
// * ПараметрыВыборки - см. ОбновлениеИнформационнойБазы.ДополнительныеПараметрыВыборкиДанныхДляМногопоточнойОбработки
// * ПорцииДляОбновления - см. НоваяТаблицаПорцийДляОбновления
// * ПоследняяВыбраннаяЗапись - СписокЗначений - описание начала отбора при страничной выборке:
// ** Представление - Строка - имя поля.
// ** Значение - Произвольный - значение поля.
// * ПоискЗавершен - Булево - Истина, поиск больше выполняться не будет (завершен).
// * ОбработкаЗавершена - Булево - признак завершения обработки, заполняемый обработчиком обновления.
// * ИмяОбработчика - Строка - имя обработчика обновления.
// * Очередь - Число - номер очереди обработчика обновления.
// * ПроцедураЗаполнения - Строка - имя процедуры заполнения данных для обновления.
// * Статус - Строка - статус обработки данных.
//
Функция НовоеОписаниеОбрабатываемыхДанных(Многопоточное = Ложь, Фоновое = Ложь) Экспорт
Описание = Новый Структура;
Описание.Вставить("ДанныеОбработчика");
Описание.Вставить("ИмяОбработчика");
Если Многопоточное Тогда
Описание.Вставить("ВыполняетсяПоискПорции", Ложь);
Описание.Вставить("ПараметрыВыборки");
Описание.Вставить("ПорцииДляОбновления");
Описание.Вставить("ПоследняяВыбраннаяЗапись");
Описание.Вставить("ПоискЗавершен", Ложь);
КонецЕсли;
Если Фоновое Тогда
Описание.Вставить("Очередь");
Описание.Вставить("ПроцедураЗаполнения");
Описание.Вставить("Статус");
КонецЕсли;
Возврат Описание;
КонецФункции
// Отбор для процедуры НайтиПорциюДляОбновления().
// Если заполнена ПоследняяВыбраннаяЗапись, то выполняется поиск первых 10000 записей после нее.
// Иначе выполняется поиск записей между ПерваяЗапись и ПоследняяЗапись.
//
// Возвращаемое значение:
// Структура - отбор со следующими полями:
// * ИдентификаторПорции - УникальныйИдентификатор - идентификатор порции для которой ищутся данные.
// * КонтекстОбработчика - см. НовыйКонтекстОбработчика
// * ПоследняяВыбраннаяЗапись - СписокЗначений - описание начала отбора при страничной выборке:
// ** Представление - Строка - имя поля.
// ** Значение - Произвольный - значение поля.
// * ПерваяЗапись - СписокЗначений - первая запись в порции, где:
// ** Представление - Строка - имя поля.
// ** Значение - Произвольный - значение поля ключа.
// * ПоследняяЗапись - СписокЗначений - последняя запись в порции, где:
// ** Представление - Строка - имя поля.
// ** Значение - Произвольный - значение поля ключа.
// * ПараметрыВыборки - см. ОбновлениеИнформационнойБазы.ДополнительныеПараметрыВыборкиДанныхДляМногопоточнойОбработки
// * Очередь - Число - номер очереди обработчика.
//
Функция НовыеПараметрыПоискаПорции()
ПараметрыПоиска = Новый Структура;
ПараметрыПоиска.Вставить("ИдентификаторПорции");
ПараметрыПоиска.Вставить("ИмяОбработчика");
ПараметрыПоиска.Вставить("КонтекстОбработчика");
ПараметрыПоиска.Вставить("ПоследняяВыбраннаяЗапись");
ПараметрыПоиска.Вставить("ПерваяЗапись");
ПараметрыПоиска.Вставить("ПоследняяЗапись");
ПараметрыПоиска.Вставить("ПараметрыВыборки");
ПараметрыПоиска.Вставить("Очередь");
ПараметрыПоиска.Вставить("ФорсироватьОбновление", Ложь);
Возврат ПараметрыПоиска;
КонецФункции
// Ключ записи порции данных.
//
// Параметры:
// СсылочныйОбъект - Строка - полное имя объекта метаданных ссылочного типа.
// ТабличныйОбъект - Строка - полное имя объекта метаданных табличного типа.
//
// Возвращаемое значение:
// СписокЗначений из Строка
//
Функция НовыйКлючЗаписи(СсылочныйОбъект, ТабличныйОбъект)
КлючЗаписи = Новый СписокЗначений;
КлючЗаписи.Добавить(СсылочныйОбъект);
КлючЗаписи.Добавить(ТабличныйОбъект);
Возврат КлючЗаписи;
КонецФункции
// Ключ записи порции из таблицы с данными.
//
// Параметры:
// СсылочныйОбъект - Строка - полное имя объекта метаданных ссылочного типа.
// ТабличныйОбъект - Строка - полное имя объекта метаданных табличного типа.
// Данные - ТаблицаЗначений - данные порции.
// Индекс - Число - индекс строки данных для формирования ключа.
//
// Возвращаемое значение:
// СписокЗначений - ключ записи.
//
Функция НовыйКлючЗаписиИзТаблицыДанных(СсылочныйОбъект, ТабличныйОбъект, Данные, Индекс)
КлючЗаписи = НовыйКлючЗаписи(СсылочныйОбъект, ТабличныйОбъект);
Строка = Данные[Индекс];
Для каждого Колонка Из Данные.Колонки Цикл
ИмяКолонки = Колонка.Имя;
КлючЗаписи.Добавить(Строка[ИмяКолонки], ИмяКолонки);
КонецЦикла;
Возврат КлючЗаписи;
КонецФункции
// Таблица значений с описанием данных для обновления.
// Является результатом поиска данных для обновления.
//
// Возвращаемое значение:
// ТаблицаЗначений - описание порций со следующей структурой:
// * СсылочныйОбъект - Строка - имя ссылочного объекта метаданных (может быть Неопределено).
// * ТабличныйОбъект - Строка - имя табличного объекта метаданных (может быть Неопределено).
// * Данные - ТаблицаЗначений - выборка из СУБД в виде таблицы значений.
//
Функция НовыйНаборДанныхДляОбновления()
НаборДанных = Новый ТаблицаЗначений;
Колонки = НаборДанных.Колонки;
Колонки.Добавить("СсылочныйОбъект", Новый ОписаниеТипов("Строка"));
Колонки.Добавить("ТабличныйОбъект", Новый ОписаниеТипов("Строка"));
Колонки.Добавить("Данные", Новый ОписаниеТипов("ТаблицаЗначений"));
Возврат НаборДанных;
КонецФункции
// Массив описаний порций данных для обновления.
// Является результатом разбиения найденных данных на фрагменты.
//
// Возвращаемое значение:
// Массив из см. НоваяПорцияДляОбновления
//
Функция НовыйНаборПорцийДляОбновления()
Возврат Новый Массив;
КонецФункции
// Описание порции данных для обновления.
//
// Возвращаемое значение:
// Структура - описание порции со следующей структурой:
// * Идентификатор - УникальныйИдентификатор - идентификатор порции.
// * ПерваяЗапись - СписокЗначений - ключ первой записи порции, см. НовыйКлючЗаписиИзДанныхПорции.
// * ПоследняяЗапись - СписокЗначений - ключ последней записи порции, см. НовыйКлючЗаписиИзДанныхПорции.
// * НаборДанных - см. НовыйНаборДанныхДляОбновления
//
Функция НоваяПорцияДляОбновления()
Порция = Новый Структура;
Порция.Вставить("Идентификатор");
Порция.Вставить("ПерваяЗапись");
Порция.Вставить("ПоследняяЗапись");
Порция.Вставить("НаборДанных");
Возврат Порция;
КонецФункции
// Результат выполнения поиска порции.
//
// Возвращаемое значение:
// Структура - результат поиска со следующими полями:
// Количество - Число - количество выбранных записей.
// НаборДанных - см. НовыйНаборДанныхДляОбновления
// ПоискЗавершен - Булево - Истина, если искать больше нечего.
//
Функция НовыйРезультатПоискаПорции()
РезультатПоиска = Новый Структура;
РезультатПоиска.Вставить("Количество", 0);
РезультатПоиска.Вставить("НаборДанных");
РезультатПоиска.Вставить("ПоискЗавершен", Ложь);
Возврат РезультатПоиска;
КонецФункции
// Найти первую не обработанную порцию (обработка которой завершилась аварийно).
//
// Параметры:
// ПорцииДляОбновления - см. НоваяТаблицаПорцийДляОбновления
//
// Возвращаемое значение:
// СтрокаТаблицыЗначений - найденная порция.
// Неопределено - если необработанных порций нет.
//
Функция ПерваяНеобработаннаяПорция(ПорцииДляОбновления)
Если ПорцииДляОбновления <> Неопределено Тогда
Для каждого Порция Из ПорцииДляОбновления Цикл
Если Не Порция.Обрабатывается Тогда
Возврат Порция;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Возврат Неопределено;
КонецФункции
// Аналог СтрРазделить, дополненный тем, что фрагменты сокращены слева и справа.
//
// Параметры:
// Строка - Строка - разделяемая строка.
// Разделитель - Строка - разделитель элементов строки.
// ВключатьПустые - Булево - Истина, если в результат попадают пустые строки.
//
// Возвращаемое значение:
// Массив - элементы строки, разбитые по разделителю.
//
Функция СтрРазделитьСокрЛП(Строка, Разделитель, ВключатьПустые = Истина)
Массив = СтрРазделить(Строка, Разделитель, ВключатьПустые);
Для Индекс = 0 По Массив.ВГраница() Цикл
Массив[Индекс] = СокрЛП(Массив[Индекс]);
КонецЦикла;
Возврат Массив;
КонецФункции
// Определяет, является ли описание обработчика многопоточным.
//
// Возвращаемое значение:
// Булево - Истина, если описание многопоточное.
//
Функция ЭтоОписаниеДанныхМногопоточногоОбработчика(Описание)
Возврат Описание.Свойство("ПорцииДляОбновления");
КонецФункции
////////////////////////////////////////////////////////////////////////////////
// НАЧАЛЬНОЕ ЗАПОЛНЕНИЕ ИНФОРМАЦИОННОЙ БАЗЫ
// Зарегистрировать предопределенные элементы для обновления в обработчике обновления.
//
Процедура ЗарегистрироватьПредопределенныеЭлементыДляОбновления(Параметры, ОбъектМетаданных = Неопределено, ДополнительныеПараметры = Неопределено) Экспорт
ПараметрыРегистрации = ПараметрыРегистрацииПредопределенныхЭлементов();
Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") Тогда
ЗаполнитьЗначенияСвойств(ПараметрыРегистрации, ДополнительныеПараметры);
КонецЕсли;
ОбъектыСПредопределеннымиЭлементами = ?(ОбъектМетаданных <> Неопределено,
ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ОбъектМетаданных),
ОбъектыСНачальнымЗаполнением());
ОбъектыКОбработке = Новый Массив;
ШаблонаЗапроса = "ВЫБРАТЬ
| &Поля
|ИЗ
| #Таблица КАК Таблица
|ГДЕ
| Таблица.Предопределенный = ИСТИНА";
Для каждого ОбъектМетаданныхСЭлементами Из ОбъектыСПредопределеннымиЭлементами Цикл
МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ОбъектМетаданныхСЭлементами.ПолноеИмя());
ЛокализуемыеРеквизитыОбъекта = Новый Соответствие;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
ЛокализуемыеРеквизитыОбъекта = МодульМультиязычностьСервер.МультиязычныеРеквизитыОбъекта(ОбъектМетаданныхСЭлементами);
КонецЕсли;
ПредопределенныеДанные = ПредопределенныеДанныеОбъекта(ОбъектМетаданныхСЭлементами, МенеджерОбъекта, ЛокализуемыеРеквизитыОбъекта);
// Формируем запрос
ИменаРеквизитовОбъекта = Новый Массив;
Если ПараметрыРегистрации.РежимОбновления = "НовыеИИзмененные" Тогда
Для Каждого Колонка Из ПредопределенныеДанные.Колонки Цикл
Если ПустаяСтрока(Колонка.Заголовок) Тогда
ИменаРеквизитовОбъекта.Добавить(Колонка.Имя);
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
МодульМультиязычностьСервер.СформироватьИменаМультиязычныхРеквизитов(ИменаРеквизитовОбъекта, ЛокализуемыеРеквизитыОбъекта);
КонецЕсли;
Если ИменаРеквизитовОбъекта.Найти("ИмяПредопределенныхДанных") = Неопределено Тогда
ИменаРеквизитовОбъекта.Добавить("ИмяПредопределенныхДанных");
КонецЕсли;
Если ИменаРеквизитовОбъекта.Найти("Ссылка") = Неопределено Тогда
ИменаРеквизитовОбъекта.Добавить("Ссылка");
КонецЕсли;
ТекстЗапроса = СтрЗаменить(ШаблонаЗапроса, "&Поля", СтрСоединить(ИменаРеквизитовОбъекта, ", " + Символы.ПС));
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "#Таблица", ОбъектМетаданныхСЭлементами.ПолноеИмя());
Запрос = Новый Запрос(ТекстЗапроса);
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Продолжить;
КонецЕсли;
ДанныеЗапроса = РезультатЗапроса.Выбрать();
Пока ДанныеЗапроса.Следующий() Цикл
ПоставляемыеСведения = ПредопределенныеДанные.Найти(ДанныеЗапроса.ИмяПредопределенныхДанных, "ИмяПредопределенныхДанных");
Если ПоставляемыеСведения <> Неопределено Тогда
Если ПараметрыРегистрации.РежимОбновления = "Все" Тогда
ОбъектыКОбработке.Добавить(ДанныеЗапроса.Ссылка);
ИначеЕсли ПараметрыРегистрации.РежимОбновления = "НовыеИИзмененные" Тогда
Если ДанныеСодержатОтличия(ДанныеЗапроса, ИменаРеквизитовОбъекта, ПоставляемыеСведения, ЛокализуемыеРеквизитыОбъекта, ПараметрыРегистрации) Тогда
ОбъектыКОбработке.Добавить(ДанныеЗапроса.Ссылка);
КонецЕсли;
ИначеЕсли ПараметрыРегистрации.РежимОбновления = "МультиязычныеСтроки" Тогда
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
Если МодульМультиязычностьСервер.МультиязычныеСтрокиРеквизитовИзменены(
ПоставляемыеСведения, ДанныеЗапроса, ЛокализуемыеРеквизитыОбъекта, ПараметрыРегистрации) Тогда
ОбъектыКОбработке.Добавить(ДанныеЗапроса.Ссылка);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Если ОбъектыКОбработке.Количество() > 0 Тогда
ОбновлениеИнформационнойБазы.ОтметитьКОбработке(Параметры, ОбъектыКОбработке);
КонецЕсли;
КонецПроцедуры
// Заполнить объект начальными данными.
//
// Параметры:
// ЗаполняемыйОбъект - СправочникОбъект
// - ПланВидовХарактеристикОбъект
// - ДанныеФормыСтруктура:
// * Ссылка - СправочникСсылка
// НастройкиЗаполнения - см. ОбновлениеИнформационнойБазы.НастройкиЗаполнения
//
Процедура ЗаполнитьОбъектНачальнымиДанными(ЗаполняемыйОбъект, НастройкиЗаполнения) Экспорт
Если ТипЗнч(ЗаполняемыйОбъект) = Тип("ДанныеФормыСтруктура") Тогда
Если ЗаполняемыйОбъект.Свойство("ИсходныйКлючЗаписи") Тогда
ТипОбъекта = ТипЗнч(ЗаполняемыйОбъект.ИсходныйКлючЗаписи);
Иначе
ТипОбъекта = ТипЗнч(ЗаполняемыйОбъект.Ссылка);
КонецЕсли;
Иначе
ТипОбъекта = ТипЗнч(ЗаполняемыйОбъект);
КонецЕсли;
МетаданныеОбъекта = Метаданные.НайтиПоТипу(ТипОбъекта);
НаборПараметровЗаполнения = НаборПараметровДляЗаполненияОбъекта(МетаданныеОбъекта);
ЗаполнитьРеквизитыНачальнымиДанными(ЗаполняемыйОбъект, НаборПараметровЗаполнения, НастройкиЗаполнения);
КонецПроцедуры
Функция ИмяКлючевогоРеквизита(НаборДанныхДляЗаполнения)
ИмяКлючевогоРеквизита = НаборДанныхДляЗаполнения.ПереопределяемыеНастройки.ИмяКлючевогоРеквизита;
Если Не ЗначениеЗаполнено(ИмяКлючевогоРеквизита) Тогда
ИмяКлючевогоРеквизита = "ИмяПредопределенныхДанных";
КонецЕсли;
Возврат ИмяКлючевогоРеквизита;
КонецФункции
Процедура ЗаполнитьЭлементыНачальнымиДанными(Параметры, ОбъектМетаданных, НастройкиЗаполнения) Экспорт
СсылкиНаОбъекты = ОбновлениеИнформационнойБазы.ВыбратьСсылкиДляОбработки(Параметры.Очередь, ОбъектМетаданных.ПолноеИмя());
Если НастройкиЗаполнения.ОбновитьТолькоМультиязычныеСтроки Тогда
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
Результат = МодульМультиязычностьСервер.ОбновитьМультиязычныеСтрокиПредопределенныхЭлементов(СсылкиНаОбъекты, ОбъектМетаданных);
КонецЕсли;
Иначе
Результат = ОбновитьЭлементыПредопределенныхЭлементов(СсылкиНаОбъекты, ОбъектМетаданных, НастройкиЗаполнения);
КонецЕсли;
Параметры.ОбработкаЗавершена = ОбновлениеИнформационнойБазы.ОбработкаДанныхЗавершена(Параметры.Очередь, ОбъектМетаданных.ПолноеИмя());
Если Результат.ОбъектовОбработано = 0 И Результат.ПроблемныхОбъектов <> 0 Тогда
ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось заполнить начальными данными некоторые элементы (пропущены): %1'"),
Результат.ПроблемныхОбъектов);
ВызватьИсключение ТекстСообщения;
Иначе
ЗаписьЖурналаРегистрации(ОбновлениеИнформационнойБазы.СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Информация,
ОбъектМетаданных,, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Обработана очередная порция элементов: %1'"),
Результат.ОбъектовОбработано));
КонецЕсли;
КонецПроцедуры
Функция ПараметрыРегистрацииПредопределенныхЭлементов()
ДополнительныеПараметры = Новый Структура;
ДополнительныеПараметры.Вставить("РежимОбновления", "НовыеИИзмененные");
ДополнительныеПараметры.Вставить("ПропускатьПустые", Истина);
ДополнительныеПараметры.Вставить("СравниватьТабличныеЧасти", Ложь);
Возврат ДополнительныеПараметры;
КонецФункции
Функция ДанныеСодержатОтличия(ДанныеЗапроса, ИмяРеквизитОбъекта, ПоставляемыеСведения, ЛокализуемыеРеквизитыОбъекта, ПараметрыРегистрации)
Для каждого ИмяРеквизитаОбъекта Из ИмяРеквизитОбъекта Цикл
Если СтрСравнить(ИмяРеквизитаОбъекта, "Предопределенный") = 0
Или СтрСравнить(ИмяРеквизитаОбъекта, "Ссылка") = 0 Тогда
Продолжить;
КонецЕсли;
ИмяРеквизитаБезСуффиксаЯзык= ИмяРеквизитаОбъекта;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
ИмяРеквизитаБезСуффиксаЯзык = МодульМультиязычностьСервер.ИмяРеквизитаБезСуффиксаЯзык(ИмяРеквизитаОбъекта);
КонецЕсли;
Если ЛокализуемыеРеквизитыОбъекта[ИмяРеквизитаБезСуффиксаЯзык] = Неопределено Тогда
Если ТипЗнч(ПоставляемыеСведения[ИмяРеквизитаОбъекта]) = Тип("ТаблицаЗначений")
И ТипЗнч(ДанныеЗапроса[ИмяРеквизитаОбъекта]) = Тип("РезультатЗапроса") Тогда
Если ПараметрыРегистрации.СравниватьТабличныеЧасти Тогда
ТаблицаДанных = ДанныеЗапроса[ИмяРеквизитаОбъекта].Выгрузить();
Если Не ОбщегоНазначения.КоллекцииИдентичны(ПоставляемыеСведения[ИмяРеквизитаОбъекта], ТаблицаДанных) Тогда
Возврат Истина;
КонецЕсли;
КонецЕсли;
Иначе
Если ПараметрыРегистрации.ПропускатьПустые И ПустаяСтрока(ПоставляемыеСведения[ИмяРеквизитаОбъекта]) Тогда
Продолжить;
КонецЕсли;
Если ПоставляемыеСведения[ИмяРеквизитаОбъекта] <> ДанныеЗапроса[ИмяРеквизитаОбъекта] Тогда
Возврат Истина;
КонецЕсли;
КонецЕсли;
Иначе
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
Если МодульМультиязычностьСервер.МультиязычныеСтрокиРеквизитаИзменены(ПоставляемыеСведения, ДанныеЗапроса,
ИмяРеквизитаБезСуффиксаЯзык, ПараметрыРегистрации) Тогда
Возврат Истина;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
// Общие для начального заполнения
// Переопределяемые настройки заполнения элементов
//
// Возвращаемое значение:
// Структура:
// * ПриНачальномЗаполненииЭлемента - Булево
// * ИмяКлючевогоРеквизита - Строка
// * ДополнительныеПараметры - Структура
//
Функция ПользовательскиеНастройкиЗаполненияЭлементов()
НастройкиЗаполненияЭлементов = Новый Структура;
НастройкиЗаполненияЭлементов.Вставить("ПриНачальномЗаполненииЭлемента", Ложь);
НастройкиЗаполненияЭлементов.Вставить("ИмяКлючевогоРеквизита", "ИмяПредопределенныхДанных");
НастройкиЗаполненияЭлементов.Вставить("ДополнительныеПараметры", Новый Структура);
Возврат НастройкиЗаполненияЭлементов;
КонецФункции
Процедура ЗаполнитьРеквизитыНачальнымиДанными(ЗаполняемыйЭлемент, НаборДанныхДляЗаполнения, НастройкиЗаполнения)
ИмяКлючевогоРеквизита = ИмяКлючевогоРеквизита(НаборДанныхДляЗаполнения.НастройкиПредопределенныхЭлементов);
ЗначениеКлючаОбъекта = ЗаполняемыйЭлемент[ИмяКлючевогоРеквизита];
Если Не ЗначениеЗаполнено(ЗначениеКлючаОбъекта) Тогда
Если Не НаборДанныхДляЗаполнения.НастройкиПредопределенныхЭлементов.ЕстьКолонкаИмяПредопределенныхДанных Тогда
Возврат;
КонецЕсли;
ИмяКлючевогоРеквизита = "ИмяПредопределенныхДанных";
ЗначениеКлючаОбъекта = ЗаполняемыйЭлемент[ИмяКлючевогоРеквизита];
Если Не ЗначениеЗаполнено(ЗначениеКлючаОбъекта) Тогда
Возврат;
КонецЕсли;
КонецЕсли;
МенеджерОбъекта = НаборДанныхДляЗаполнения.МенеджерОбъекта;
СтрокаТаблицы = НаборДанныхДляЗаполнения.ПредопределенныеДанные.Найти(ЗначениеКлючаОбъекта, ИмяКлючевогоРеквизита);
Если СтрокаТаблицы = Неопределено Тогда
Возврат;
КонецЕсли;
КромеРеквизитов = НаборДанныхДляЗаполнения.РеквизитыИсключения;
Если НаборДанныхДляЗаполнения.ПоддерживаетсяИерархия И ЗаполняемыйЭлемент.ЭтоГруппа Тогда
КромеРеквизитов = НаборДанныхДляЗаполнения.РеквизитыИсключения
+ ?(ПустаяСтрока(НаборДанныхДляЗаполнения.РеквизитыИсключения), "", ",") + СтрСоединить(НаборДанныхДляЗаполнения.РеквизитыСЭлементами, ",");
КонецЕсли;
Если Не НастройкиЗаполнения.ОбновитьТолькоМультиязычныеСтроки Тогда
Если ЗначениеЗаполнено(НастройкиЗаполнения.Реквизиты) Тогда
ЗаполнитьЗначенияСвойств(ЗаполняемыйЭлемент, СтрокаТаблицы, НастройкиЗаполнения.Реквизиты);
Иначе
ЗаполнитьЗначенияСвойств(ЗаполняемыйЭлемент, СтрокаТаблицы,, КромеРеквизитов);
КонецЕсли;
Если НаборДанныхДляЗаполнения.ПоддерживаетсяИерархия И ЗначениеЗаполнено(СтрокаТаблицы.Родитель) Тогда
Если ИмяКлючевогоРеквизита = "Ссылка" Тогда
Если ТипЗнч(СтрокаТаблицы.Родитель) = Тип("Строка") Тогда
ЗаполняемыйЭлемент.Родитель = МенеджерОбъекта.ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаТаблицы.Родитель));
ИначеЕсли ТипЗнч(СтрокаТаблицы.Родитель) = Тип("УникальныйИдентификатор") Тогда
ЗаполняемыйЭлемент.Родитель = МенеджерОбъекта.ПолучитьСсылку(СтрокаТаблицы.Родитель);
Иначе
ЗаполняемыйЭлемент.Родитель = СтрокаТаблицы.Родитель;
КонецЕсли;
ИначеЕсли ТипЗнч(СтрокаТаблицы.Родитель) = Тип("Строка") Тогда
МетаданныеОбъекта = Метаданные.НайтиПоТипу(ТипЗнч(ЗаполняемыйЭлемент));
СуществующиеЭлементы = СуществующиеПоставляемыеЭлементы(НаборДанныхДляЗаполнения.ПредопределенныеДанные,
НаборДанныхДляЗаполнения.НастройкиПредопределенныхЭлементов, МенеджерОбъекта, МетаданныеОбъекта);
ЗаполняемыйЭлемент.Родитель = СуществующиеЭлементы[СтрокаТаблицы.Родитель];
Иначе
ЗаполняемыйЭлемент.Родитель = СтрокаТаблицы.Родитель;
КонецЕсли;
КонецЕсли;
Если НЕ (НаборДанныхДляЗаполнения.ПоддерживаетсяИерархия И ЗаполняемыйЭлемент.ЭтоГруппа) Тогда
Для Каждого ИмяТабличнойЧасти Из НаборДанныхДляЗаполнения.ТабличныеЧасти Цикл
ЗаполняемыйЭлемент[ИмяТабличнойЧасти].Загрузить(СтрокаТаблицы[ИмяТабличнойЧасти]);
КонецЦикла;
КонецЕсли;
КонецЕсли;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
МодульМультиязычностьСервер.ЗаполнитьЭлементыМультиязычнымиНачальнымиДанными(ЗаполняемыйЭлемент,
НаборДанныхДляЗаполнения.ЛокализуемыеРеквизитыОбъекта, НаборДанныхДляЗаполнения.МультиязычныеСтрокиВРеквизитах,
НаборДанныхДляЗаполнения.ПоддерживаетсяИерархия, СтрокаТаблицы);
КонецЕсли;
Если НаборДанныхДляЗаполнения.НастройкиПредопределенныхЭлементов.ПереопределяемыеНастройки.ПриНачальномЗаполненииЭлемента Тогда
МенеджерОбъекта.ПриНачальномЗаполненииЭлемента(ЗаполняемыйЭлемент, СтрокаТаблицы, НаборДанныхДляЗаполнения.НастройкиПредопределенныхЭлементов.ПереопределяемыеНастройки.ДополнительныеПараметры);
КонецЕсли;
КонецПроцедуры
// Обновить элементы предопределенных элементов в обработчиках обновления
//
// Параметры:
// СсылкиНаОбъекты - ВыборкаИзРезультатаЗапроса - ссылки на объекты:
// * Ссылка - ЛюбаяСсылка
// МетаданныеОбъекта - ОбъектМетаданных
// НастройкиЗаполнения - см. ОбновлениеИнформационнойБазы.НастройкиЗаполнения
//
// Возвращаемое значение:
// Структура - обновить элементы предопределенных элементов:
// * ПроблемныхОбъектов - Число
// * ОбъектовОбработано - Число
//
Функция ОбновитьЭлементыПредопределенныхЭлементов(СсылкиНаОбъекты, МетаданныеОбъекта, НастройкиЗаполнения)
Результат = Новый Структура();
Результат.Вставить("ПроблемныхОбъектов", 0);
Результат.Вставить("ОбъектовОбработано", 0);
ПараметрыДляЗаполненияОбъекта = НаборПараметровДляЗаполненияОбъекта(МетаданныеОбъекта);
ИмяКлючевогоРеквизита = ИмяКлючевогоРеквизита(ПараметрыДляЗаполненияОбъекта.НастройкиПредопределенныхЭлементов);
ПоддерживаетсяИерархия = ПараметрыДляЗаполненияОбъекта.ПоддерживаетсяИерархия;
РеквизитыИсключения = ПараметрыДляЗаполненияОбъекта.РеквизитыИсключения;
МенеджерОбъекта = ПараметрыДляЗаполненияОбъекта.МенеджерОбъекта;
Пока СсылкиНаОбъекты.Следующий() Цикл
СсылкаНаОбъект = СсылкиНаОбъекты.Ссылка;
ЗначениеКлючевогоРеквизита = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаНаОбъект, ИмяКлючевогоРеквизита);
Если Не ЗначениеЗаполнено(ЗначениеКлючевогоРеквизита) Тогда
Результат.ОбъектовОбработано = Результат.ОбъектовОбработано + 1;
ОбновлениеИнформационнойБазы.ОтметитьВыполнениеОбработки(СсылкиНаОбъекты.Ссылка);
Продолжить;
КонецЕсли;
СтрокаТаблицы = ПараметрыДляЗаполненияОбъекта.ПредопределенныеДанные.Найти(ЗначениеКлючевогоРеквизита, ИмяКлючевогоРеквизита);
Если СтрокаТаблицы = Неопределено Тогда
Результат.ОбъектовОбработано = Результат.ОбъектовОбработано + 1;
ОбновлениеИнформационнойБазы.ОтметитьВыполнениеОбработки(СсылкиНаОбъекты.Ссылка);
Продолжить;
КонецЕсли;
НачатьТранзакцию();
Попытка
БлокировкаДанных = Новый БлокировкаДанных;
ЭлементБлокировкиДанных = БлокировкаДанных.Добавить(МетаданныеОбъекта.ПолноеИмя());
ЭлементБлокировкиДанных.УстановитьЗначение("Ссылка", СсылкиНаОбъекты.Ссылка);
БлокировкаДанных.Заблокировать();
ЗаполняемыйЭлемент = СсылкиНаОбъекты.Ссылка.ПолучитьОбъект();
КромеРеквизитов = РеквизитыИсключения;
Если ПоддерживаетсяИерархия И ЗаполняемыйЭлемент.ЭтоГруппа Тогда
КромеРеквизитов = РеквизитыИсключения
+ ?(ПустаяСтрока(РеквизитыИсключения), "", ",") + СтрСоединить(ПараметрыДляЗаполненияОбъекта.РеквизитыСЭлементами, ",");
КонецЕсли;
Если ЗначениеЗаполнено(НастройкиЗаполнения.Реквизиты) Тогда
ЗаполнитьЗначенияСвойств(ЗаполняемыйЭлемент, СтрокаТаблицы, НастройкиЗаполнения.Реквизиты);
Иначе
ЗаполнитьЗначенияСвойств(ЗаполняемыйЭлемент, СтрокаТаблицы,, КромеРеквизитов);
КонецЕсли;
Если НЕ (ПоддерживаетсяИерархия И ЗаполняемыйЭлемент.ЭтоГруппа) Тогда
Для Каждого ИмяТабличнойЧасти Из ПараметрыДляЗаполненияОбъекта.ТабличныеЧасти Цикл
ЗаполняемыйЭлемент[ИмяТабличнойЧасти].Загрузить(СтрокаТаблицы[ИмяТабличнойЧасти]);
КонецЦикла;
КонецЕсли;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
МодульМультиязычностьСервер.ЗаполнитьЭлементыМультиязычнымиНачальнымиДанными(ЗаполняемыйЭлемент,
ПараметрыДляЗаполненияОбъекта.ЛокализуемыеРеквизитыОбъекта, ПараметрыДляЗаполненияОбъекта.МультиязычныеСтрокиВРеквизитах,
ПоддерживаетсяИерархия, СтрокаТаблицы);
КонецЕсли;
Если ПараметрыДляЗаполненияОбъекта.НастройкиПредопределенныхЭлементов.ПереопределяемыеНастройки.ПриНачальномЗаполненииЭлемента Тогда
МенеджерОбъекта.ПриНачальномЗаполненииЭлемента(ЗаполняемыйЭлемент, СтрокаТаблицы,
ПараметрыДляЗаполненияОбъекта.НастройкиПредопределенныхЭлементов.ПереопределяемыеНастройки.ДополнительныеПараметры);
КонецЕсли;
ОбновлениеИнформационнойБазы.ЗаписатьОбъект(ЗаполняемыйЭлемент);
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
// Если не удалось обработать элемент, повторяем попытку снова.
Результат.ПроблемныхОбъектов = Результат.ПроблемныхОбъектов + 1;
ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Не удалось заполнить элемент: %1 по причине: %2'"),
СсылкиНаОбъекты.Ссылка, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ЗаписьЖурналаРегистрации(ОбновлениеИнформационнойБазы.СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Предупреждение,
МетаданныеОбъекта, СсылкиНаОбъекты.Ссылка, ТекстСообщения);
КонецПопытки;
Результат.ОбъектовОбработано = Результат.ОбъектовОбработано + 1;
КонецЦикла;
Возврат Результат;
КонецФункции
Функция СуществующиеПоставляемыеЭлементы(ПредопределенныеДанные, НастройкиПредопределенныхЭлементов, Знач МенеджерОбъекта, МетаданныеОбъекта)
Результат = Новый Соответствие();
ИмяКлючевогоРеквизита = НастройкиПредопределенныхЭлементов.ПереопределяемыеНастройки.ИмяКлючевогоРеквизита;
ЕстьКолонкаИмяПредопределенныхДанных = НастройкиПредопределенныхЭлементов.ЕстьКолонкаИмяПредопределенныхДанных;
ИменаПредопределенных = МетаданныеОбъекта.ПолучитьИменаПредопределенных();
НаборКлючей = Новый ТаблицаЗначений();
Если ИмяКлючевогоРеквизита <> "Ссылка" Тогда
НаборКлючей.Колонки.Добавить("Ключ", ОбщегоНазначения.ОписаниеТипаСтрока(150));
Иначе
Массив = Новый Массив;
Массив.Добавить(ТипЗнч(МенеджерОбъекта.ПустаяСсылка()));
НаборКлючей.Колонки.Добавить("Ключ", Новый ОписаниеТипов(Массив));
КонецЕсли;
Результат = Новый Соответствие();
Если СтрСравнить(ИмяКлючевогоРеквизита, "ИмяПредопределенныхДанных") <> 0 Тогда
Для Каждого ПредопределенныйЭлемент Из ПредопределенныеДанные Цикл
Если ЕстьКолонкаИмяПредопределенныхДанных
И ЗначениеЗаполнено(ПредопределенныйЭлемент.ИмяПредопределенныхДанных)
И ИменаПредопределенных.Найти(ПредопределенныйЭлемент.ИмяПредопределенныхДанных) <> Неопределено Тогда
Результат.Вставить(ПредопределенныйЭлемент.ИмяПредопределенныхДанных, МенеджерОбъекта[ПредопределенныйЭлемент.ИмяПредопределенныхДанных]);
Продолжить;
КонецЕсли;
Если ЗначениеЗаполнено(ПредопределенныйЭлемент[ИмяКлючевогоРеквизита]) Тогда
НоваяСтрока = НаборКлючей.Добавить();
НоваяСтрока.Ключ = ПредопределенныйЭлемент[ИмяКлючевогоРеквизита];
КонецЕсли;
КонецЦикла;
Если НаборКлючей.Количество() > 0 Тогда
Запрос = Новый Запрос;
ТекстЗапроса = "ВЫБРАТЬ
| НаборКлючей.Ключ КАК ИмяКлючевогоРеквизита
|ПОМЕСТИТЬ НаборКлючей
|ИЗ
| &НаборКлючей КАК НаборКлючей
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ЕСТЬNULL(ТаблицаДанных.Ссылка, НЕОПРЕДЕЛЕНО) КАК Ссылка,
| НаборКлючей.ИмяКлючевогоРеквизита КАК ИмяКлючевогоРеквизита
|ИЗ
| НаборКлючей КАК НаборКлючей
| ЛЕВОЕ СОЕДИНЕНИЕ #Таблица КАК ТаблицаДанных
| ПО НаборКлючей.ИмяКлючевогоРеквизита = &ИмяПоля";
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяПоля", "ТаблицаДанных." + ИмяКлючевогоРеквизита);
Запрос.Текст = СтрЗаменить(ТекстЗапроса, "#Таблица", МетаданныеОбъекта.ПолноеИмя());
Запрос.УстановитьПараметр("НаборКлючей", НаборКлючей);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
Результат.Вставить(ВыборкаДетальныеЗаписи.ИмяКлючевогоРеквизита, ВыборкаДетальныеЗаписи.Ссылка);
КонецЦикла;
КонецЕсли;
ИначеЕсли ЕстьКолонкаИмяПредопределенныхДанных Тогда
Для Каждого ПоставляемыйЭлемент Из ПредопределенныеДанные Цикл
Если ЗначениеЗаполнено(ПоставляемыйЭлемент["ИмяПредопределенныхДанных"]) Тогда
Результат.Вставить(ПоставляемыйЭлемент["ИмяПредопределенныхДанных"], МенеджерОбъекта[ПоставляемыйЭлемент[ИмяКлючевогоРеквизита]]);
Продолжить;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Возврат Результат;
КонецФункции
Процедура ДобавитьКолонкуТаблицыПредопределенныхДанных(ПредопределенныеДанные, Реквизит, ЛокализуемыеРеквизиты, Языки)
Если СтрСравнить(Реквизит.Имя, "Родитель") = 0 Тогда
МассивТипов = Новый Массив;
Для Каждого ТипРеквизита Из Реквизит.Тип.Типы() Цикл
МассивТипов.Добавить(ТипРеквизита);
КонецЦикла;
МассивТипов.Добавить(Тип("Строка"));
ПараметрыСтроки = Новый КвалификаторыСтроки(150);
ТипРеквизита = Новый ОписаниеТипов(МассивТипов,, ПараметрыСтроки);
ИначеЕсли СтрСравнить(Реквизит.Имя, "Ссылка") = 0 Тогда
МассивТипов = Новый Массив;
Для Каждого ТипРеквизита Из Реквизит.Тип.Типы() Цикл
МассивТипов.Добавить(ТипРеквизита);
КонецЦикла;
МассивТипов.Добавить(Тип("Строка"));
МассивТипов.Добавить(Тип("УникальныйИдентификатор"));
ПараметрыСтроки = Новый КвалификаторыСтроки(150);
ТипРеквизита = Новый ОписаниеТипов(МассивТипов,, ПараметрыСтроки);
Иначе
ТипРеквизита = Реквизит.Тип;
КонецЕсли;
ПредопределенныеДанные.Колонки.Добавить(Реквизит.Имя, ТипРеквизита);
Если ЛокализуемыеРеквизиты[Реквизит.Имя] = Неопределено Тогда
Возврат;
КонецЕсли;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
МодульМультиязычностьСервер = ОбщегоНазначения.ОбщийМодуль("МультиязычностьСервер");
Иначе
Возврат;
КонецЕсли;
Для Каждого Язык Из Языки Цикл
ПредопределенныеДанные.Колонки.Добавить(Реквизит.Имя + "_" + Язык, Реквизит.Тип,
МодульМультиязычностьСервер.ПризнакЛокализуемогоРеквизита());
КонецЦикла;
КонецПроцедуры
////////////////////////////////////////////////////////////////////////////////
// ОБРАБОТЧИКИ ОБНОВЛЕНИЯ ИНФОРМАЦИОННОЙ БАЗЫ
// Устанавливает ключ регламентного задания ОтложенноеОбновлениеИБ.
//
Процедура УстановитьКлючРегламентногоЗадания() Экспорт
Отбор = Новый Структура;
Отбор.Вставить("Метаданные", Метаданные.РегламентныеЗадания.ОтложенноеОбновлениеИБ);
Отбор.Вставить("Предопределенное", Истина);
Задания = РегламентныеЗаданияСервер.НайтиЗадания(Отбор);
Для Каждого Задание Из Задания Цикл
Если ЗначениеЗаполнено(Задание.Ключ) Тогда
Продолжить;
КонецЕсли;
Задание.Ключ = Метаданные.РегламентныеЗадания.ОтложенноеОбновлениеИБ.Ключ;
Задание.Записать(); // АПК:1363 регламентное задание не участвует в обменах.
КонецЦикла;
КонецПроцедуры
////////////////////////////////////////////////////////////////////////////////
// ВСПОМОГАТЕЛЬНЫЕ ПРОЦЕДУРЫ И ФУНКЦИИ
////////////////////////////////////////////////////////////////////////////////
// Общего назначения
Процедура ОтключитьОбновлениеКлючейДоступа(Значение, ПодсистемаСуществует)
Если ПодсистемаСуществует Тогда
МодульУправлениеДоступом = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступом");
МодульУправлениеДоступом.ОтключитьОбновлениеКлючейДоступа(Значение);
КонецЕсли;
КонецПроцедуры
Функция РежимОбновленияДанныхВЛокальномРежимеРаботы()
УстановитьПривилегированныйРежим(Истина);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| 1 КАК ЕстьВерсииПодсистем
|ИЗ
| РегистрСведений.ВерсииПодсистем КАК ВерсииПодсистем";
РезультатВыполненияПакета = Запрос.ВыполнитьПакет();
Если РезультатВыполненияПакета[0].Пустой() Тогда
Возврат "НачальноеЗаполнение";
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| 1 КАК ЕстьВерсииПодсистем
|ИЗ
| РегистрСведений.ВерсииПодсистем КАК ВерсииПодсистем
|ГДЕ
| ВерсииПодсистем.ЭтоОсновнаяКонфигурация = ИСТИНА
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| 1 КАК ЕстьВерсииПодсистем
|ИЗ
| РегистрСведений.ВерсииПодсистем КАК ВерсииПодсистем
|ГДЕ
| ВерсииПодсистем.ИмяПодсистемы = &ИмяОсновнойКонфигурации
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| 1 КАК ЕстьВерсииПодсистем
|ИЗ
| РегистрСведений.ВерсииПодсистем КАК ВерсииПодсистем
|ГДЕ
| ВерсииПодсистем.ЭтоОсновнаяКонфигурация = ИСТИНА
| И ВерсииПодсистем.ИмяПодсистемы = &ИмяОсновнойКонфигурации";
Запрос.УстановитьПараметр("ИмяОсновнойКонфигурации", Метаданные.Имя);
РезультатВыполненияПакета = Запрос.ВыполнитьПакет();
Если РезультатВыполненияПакета[0].Пустой() И Не РезультатВыполненияПакета[1].Пустой() Тогда
Возврат "ОбновлениеВерсии"; // Признак ЭтоОсновнаяКонфигурация еще не был заполнен.
КонецЕсли;
// Определяем по ранее заполненному признаку ЭтоОсновнаяКонфигурация.
Возврат ?(РезультатВыполненияПакета[2].Пустой(), "ПереходСДругойПрограммы", "ОбновлениеВерсии");
КонецФункции
// АПК:581-выкл используется для тестирования.
Функция ВозможноОперативноеОбновление(ПроверяемыеИтерацииОбновления = Неопределено) Экспорт
Если ПроверяемыеИтерацииОбновления = Неопределено Тогда
// Режим вызова для определения полного состава процедур обработчиков обновления,
// требующих монопольный режим (без записи сообщений в журнал регистрации).
ИтерацииОбновления = ИтерацииОбновления();
Иначе
ИтерацииОбновления = ПроверяемыеИтерацииОбновления;
КонецЕсли;
ФильтрыРазделенностиОбработчиков = Новый Массив;
Если НЕ ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
ФильтрыРазделенностиОбработчиков.Добавить(Ложь);
КонецЕсли;
ФильтрыРазделенностиОбработчиков.Добавить(Истина);
// В режиме проверки параметр не используется.
ОбязательныеРазделенныеОбработчики = ОбновлениеИнформационнойБазы.НоваяТаблицаОбработчиковОбновления();
ЗаписыватьВЖурнал = Константы.ДетализироватьОбновлениеИБВЖурналеРегистрации.Получить();
ПроцедурыОбработчиков = Новый Массив;
// Проверяем обработчики обновления с флагом МонопольныйРежим для подсистем конфигурации.
Для каждого ИтерацияОбновления Из ИтерацииОбновления Цикл
ПараметрыОтбора = ПараметрыОтбораОбработчиков();
ПараметрыОтбора.РежимОбновления = "Оперативно";
Для каждого ФлагРазделенности Из ФильтрыРазделенностиОбработчиков Цикл
ПараметрыОтбора.ПолучатьРазделенные = ФлагРазделенности;
ДеревоОбработчиков = ОбработчикиОбновленияВИнтервале(ИтерацияОбновления.Обработчики, ИтерацияОбновления.ПредыдущаяВерсия,
ИтерацияОбновления.Версия, ПараметрыОтбора);
Если ДеревоОбработчиков.Строки.Количество() = 0 Тогда
Продолжить;
КонецЕсли;
Если ДеревоОбработчиков.Строки.Количество() > 1
ИЛИ ДеревоОбработчиков.Строки[0].Версия <> "*" Тогда
Для Каждого СтрокаВерсия Из ДеревоОбработчиков.Строки Цикл
Если СтрокаВерсия.Версия = "*" Тогда
Продолжить;
КонецЕсли;
Для Каждого Обработчик Из СтрокаВерсия.Строки Цикл
ПроцедурыОбработчиков.Добавить(Обработчик.Процедура);
КонецЦикла;
КонецЦикла;
КонецЕсли;
Если ФлагРазделенности
И ОбщегоНазначения.РазделениеВключено()
И НЕ ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
// При обновлении неразделенной версии ИБ, для разделенных обязательных
// обработчиков обновления монопольным режимом управляет неразделенный обработчик.
Продолжить;
КонецЕсли;
НайденныеОбработчики = ДеревоОбработчиков.Строки[0].Строки.НайтиСтроки(Новый Структура("МонопольныйРежим", Неопределено));
Для Каждого Обработчик Из НайденныеОбработчики Цикл
ПроцедурыОбработчиков.Добавить(Обработчик.Процедура);
КонецЦикла;
// Вызов обязательных обработчиков обновления в режиме проверки.
Для каждого Обработчик Из ДеревоОбработчиков.Строки[0].Строки Цикл
Если Обработчик.ВерсияРегистрации <> "*" Тогда
ПроцедурыОбработчиков.Добавить(Обработчик.Процедура);
Продолжить;
КонецЕсли;
ПараметрыОбработчика = Новый Структура;
Если Обработчик.УправлениеОбработчиками Тогда
ПараметрыОбработчика.Вставить("РазделенныеОбработчики", ОбязательныеРазделенныеОбработчики);
КонецЕсли;
ПараметрыОбработчика.Вставить("МонопольныйРежим", Ложь);
ДополнительныеПараметры = Новый Структура;
ДополнительныеПараметры.Вставить("ЗаписыватьВЖурнал", ЗаписыватьВЖурнал);
ДополнительныеПараметры.Вставить("ИдентификаторБиблиотеки", ИтерацияОбновления.Подсистема);
ДополнительныеПараметры.Вставить("ХодВыполненияОбработчиков", Неопределено);
ДополнительныеПараметры.Вставить("ВФоне", Ложь);
ВыполнитьОбработчикОбновления(Обработчик, ПараметрыОбработчика, ДополнительныеПараметры);
Если ПараметрыОбработчика.МонопольныйРежим = Истина Тогда
ПроцедурыОбработчиков.Добавить(Обработчик.Процедура);
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецЦикла;
Если ПроверяемыеИтерацииОбновления = Неопределено Тогда
ПроверяемыеИтерацииОбновления = ПроцедурыОбработчиков;
Возврат ПроцедурыОбработчиков.Количество() = 0;
КонецЕсли;
Если ПроцедурыОбработчиков.Количество() <> 0 Тогда
ТекстСообщения = НСтр("ru = 'Следующие обработчики не поддерживают обновление без установки монопольного режима:'");
ТекстСообщения = ТекстСообщения + Символы.ПС;
Для Каждого ПроцедураОбработчика Из ПроцедурыОбработчиков Цикл
ТекстСообщения = ТекстСообщения + Символы.ПС + ПроцедураОбработчика;
КонецЦикла;
ЗаписатьОшибку(ТекстСообщения);
КонецЕсли;
Возврат ПроцедурыОбработчиков.Количество() = 0;
КонецФункции
// АПК:581-вкл.
Процедура СкопироватьСтрокиВДерево(Знач СтрокиПриемника, Знач СтрокиИсточника, Знач СтруктураКолонок)
Для каждого СтрокаИсточника Из СтрокиИсточника Цикл
ЗаполнитьЗначенияСвойств(СтруктураКолонок, СтрокаИсточника);
НайденныеСтроки = СтрокиПриемника.НайтиСтроки(СтруктураКолонок);
Если НайденныеСтроки.Количество() = 0 Тогда
СтрокаПриемника = СтрокиПриемника.Добавить();
ЗаполнитьЗначенияСвойств(СтрокаПриемника, СтрокаИсточника);
Иначе
СтрокаПриемника = НайденныеСтроки[0];
КонецЕсли;
СкопироватьСтрокиВДерево(СтрокаПриемника.Строки, СтрокаИсточника.Строки, СтруктураКолонок);
КонецЦикла;
КонецПроцедуры
Функция ПолучитьПланОбновления(Знач ИдентификаторБиблиотеки, Знач ВерсияС, Знач ВерсияНа)
МенеджерЗаписи = РегистрыСведений.ВерсииПодсистем.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ИмяПодсистемы = ИдентификаторБиблиотеки;
МенеджерЗаписи.Прочитать();
Если НЕ МенеджерЗаписи.Выбран() Тогда
Возврат Неопределено;
КонецЕсли;
ОписаниеПлана = МенеджерЗаписи.ПланОбновления.Получить();
Если ОписаниеПлана = Неопределено Тогда
Возврат Неопределено;
Иначе
Если ОписаниеПлана.ВерсияС <> ВерсияС
ИЛИ ОписаниеПлана.ВерсияНа <> ВерсияНа Тогда
// План устарел и не соответствует текущей версии.
Возврат Неопределено;
КонецЕсли;
Возврат ОписаниеПлана.План;
КонецЕсли;
КонецФункции
Процедура ВыполнитьОбработчикОбновления(Обработчик, Параметры, ДополнительныеПараметры)
ЗаписатьИнформациюОХодеОбновления(Обработчик, ДополнительныеПараметры.ХодВыполненияОбработчиков, ДополнительныеПараметры.ВФоне);
ОписаниеОбработчика =
ПодготовитьДетальнуюИнформациюОХодеОбновления(Обработчик, Параметры, ДополнительныеПараметры.ИдентификаторБиблиотеки);
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОценкаПроизводительности") Тогда
МодульОценкаПроизводительности = ОбщегоНазначения.ОбщийМодуль("ОценкаПроизводительности");
НачалоЗамера = МодульОценкаПроизводительности.НачатьЗамерВремени();
КонецЕсли;
Если Параметры <> Неопределено Тогда
ПараметрыОбработчика = Новый Массив;
ПараметрыОбработчика.Добавить(Параметры);
Иначе
ПараметрыОбработчика = Неопределено;
КонецЕсли;
ТранзакцияАктивнаНаНачалоВыполнения = ТранзакцияАктивна();
ПодсистемаСуществует = ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом");
ОтключитьОбновлениеКлючейДоступа(Истина, ПодсистемаСуществует);
Попытка
УстановитьПараметрыОбработчикаОбновления(Обработчик);
УстановитьСтатусОбработчика(Обработчик.Процедура, "Выполняется");
НачалоОбработки = ТекущаяУниверсальнаяДатаВМиллисекундах();
ОбщегоНазначения.ВыполнитьМетодКонфигурации(Обработчик.Процедура, ПараметрыОбработчика);
КонецОбработки = ТекущаяУниверсальнаяДатаВМиллисекундах();
УстановитьПараметрыОбработчикаОбновления(Неопределено);
УстанавливаемыеСвойства = Новый Структура;
УстанавливаемыеСвойства.Вставить("Статус", Перечисления.СтатусыОбработчиковОбновления.Выполнен);
УстанавливаемыеСвойства.Вставить("ДлительностьОбработки", КонецОбработки - НачалоОбработки);
УстановитьСвойстваОбработчика(Обработчик.Процедура, УстанавливаемыеСвойства);
ОтключитьОбновлениеКлючейДоступа(Ложь, ПодсистемаСуществует);
Исключение
ОтключитьОбновлениеКлючейДоступа(Ложь, ПодсистемаСуществует);
Если ДополнительныеПараметры.ЗаписыватьВЖурнал Тогда
ЗаписатьДетальнуюИнформациюОХодеОбновления(ОписаниеОбработчика);
КонецЕсли;
ИмяОбработчика = Обработчик.Процедура + "(" + ?(ПараметрыОбработчика = Неопределено, "", "Параметры") + ")";
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'При вызове обработчика обновления:
|""%1""
|произошла ошибка:
|""%2"".'"),
ИмяОбработчика,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ЗаписатьОшибку(ТекстОшибки);
УстановитьСтатусОбработчика(Обработчик.Процедура, "Ошибка", ТекстОшибки);
ВызватьИсключение;
КонецПопытки;
ПроверитьВложеннуюТранзакцию(ТранзакцияАктивнаНаНачалоВыполнения, Обработчик.Процедура);
Если ДополнительныеПараметры.ЗаписыватьВЖурнал Тогда
ЗаписатьДетальнуюИнформациюОХодеОбновления(ОписаниеОбработчика);
КонецЕсли;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОценкаПроизводительности") Тогда
МодульОценкаПроизводительности = ОбщегоНазначения.ОбщийМодуль("ОценкаПроизводительности");
МодульОценкаПроизводительности.ЗакончитьЗамерВремениТехнологический("ВремяВыполненияОбработчикаОбновления." + ОписаниеОбработчика.Процедура, НачалоЗамера);
КонецЕсли;
КонецПроцедуры
Процедура ВыполнитьОбработчикиПослеОбновленияИнформационнойБазы(Знач ИтерацииОбновления, Знач ЗаписыватьВЖурнал, ВыводитьОписаниеОбновлений, Знач ОперативноеОбновление)
Для Каждого ИтерацияОбновления Из ИтерацииОбновления Цикл
Если ЗаписыватьВЖурнал Тогда
Обработчик = Новый Структура();
Обработчик.Вставить("Версия", "*");
Обработчик.Вставить("ВерсияРегистрации", "*");
Обработчик.Вставить("РежимВыполнения", "Оперативно");
Обработчик.Вставить("Процедура", ИтерацияОбновления.ИмяОсновногоСерверногоМодуля + ".ПослеОбновленияИнформационнойБазы");
ОписаниеОбработчика = ПодготовитьДетальнуюИнформациюОХодеОбновления(Обработчик, Неопределено, ИтерацияОбновления.Подсистема);
КонецЕсли;
Попытка
ИтерацияОбновления.ОсновнойСерверныйМодуль.ПослеОбновленияИнформационнойБазы(
ИтерацияОбновления.ПредыдущаяВерсия,
ИтерацияОбновления.Версия,
ИтерацияОбновления.ВыполненныеОбработчики,
ВыводитьОписаниеОбновлений,
НЕ ОперативноеОбновление);
Исключение
Если ЗаписыватьВЖурнал Тогда
ЗаписатьДетальнуюИнформациюОХодеОбновления(ОписаниеОбработчика);
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
Если ЗаписыватьВЖурнал Тогда
ЗаписатьДетальнуюИнформациюОХодеОбновления(ОписаниеОбработчика);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// Параметры:
// Обработчик - Неопределено
// - СтрокаДереваЗначений
// - Структура:
// * РежимВыполнения - Строка
// * ВерсияРегистрации - Строка
// * Версия - Строка
// Параметры - Неопределено
// - Структура:
// * Очередь - Произвольный
// * ПрогрессВыполнения - Структура:
// ** ОбработаноОбъектов - Число
// ** ВсегоОбъектов - Число
// * ОбработкаЗавершена - Булево
// ИдентификаторБиблиотеки - Произвольный
// ОбработчикОтложенный - Булево
// Возвращаемое значение:
// Структура:
// * ЗначениеНаНачало - Число
// * ОбластьДанныхИспользование - Булево
// * ОбластьДанныхЗначение - Число
// * РежимВыполнения - Строка
// * Параметры - Неопределено
//
Функция ПодготовитьДетальнуюИнформациюОХодеОбновления(Обработчик, Параметры, ИдентификаторБиблиотеки, ОбработчикОтложенный = Ложь)
ОписаниеОбработчика = Новый Структура;
ОписаниеОбработчика.Вставить("Библиотека", ИдентификаторБиблиотеки);
Если ОбработчикОтложенный Тогда
ОписаниеОбработчика.Вставить("Версия", Обработчик.Версия);
ОписаниеОбработчика.Вставить("Процедура", Обработчик.ИмяОбработчика);
Иначе
ОписаниеОбработчика.Вставить("Версия", Обработчик.Версия);
ОписаниеОбработчика.Вставить("Процедура", Обработчик.Процедура);
КонецЕсли;
ОписаниеОбработчика.Вставить("ВерсияРегистрации", Обработчик.ВерсияРегистрации);
ОписаниеОбработчика.Вставить("Параметры", Параметры);
Если ОбработчикОтложенный Тогда
ОписаниеОбработчика.Вставить("РежимВыполнения", "Отложенно");
ИначеЕсли ЗначениеЗаполнено(Обработчик.РежимВыполнения) Тогда
ОписаниеОбработчика.Вставить("РежимВыполнения", Обработчик.РежимВыполнения);
Иначе
ОписаниеОбработчика.Вставить("РежимВыполнения", "Монопольно");
КонецЕсли;
Если ОбщегоНазначения.РазделениеВключено()
И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
ОписаниеОбработчика.Вставить("ОбластьДанныхЗначение",
МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса());
ОписаниеОбработчика.Вставить("ОбластьДанныхИспользование", Истина);
Иначе
ОписаниеОбработчика.Вставить("ОбластьДанныхЗначение", -1);
ОписаниеОбработчика.Вставить("ОбластьДанныхИспользование", Ложь);
КонецЕсли;
ОписаниеОбработчика.Вставить("ЗначениеНаНачало", ТекущаяУниверсальнаяДатаВМиллисекундах());
Возврат ОписаниеОбработчика;
КонецФункции
Процедура ЗаписатьДетальнуюИнформациюОХодеОбновления(ОписаниеОбработчика)
Длительность = ТекущаяУниверсальнаяДатаВМиллисекундах() - ОписаниеОбработчика.ЗначениеНаНачало;
ОписаниеОбработчика.Вставить("Выполнен", Ложь);
ОписаниеОбработчика.Вставить("Длительность", Длительность / 1000); // В секундах
КопияОписания = ОбщегоНазначения.СкопироватьРекурсивно(ОписаниеОбработчика);
Если КопияОписания.Свойство("Параметры") Тогда
КопияОписания.Удалить("Параметры");
КонецЕсли;
ЗаписьЖурналаРегистрации(
СобытиеЖурналаРегистрацииПротокол(),
УровеньЖурналаРегистрации.Информация,
,
,
ОбщегоНазначения.ЗначениеВСтрокуXML(КопияОписания));
КонецПроцедуры
Процедура ПроверитьВложеннуюТранзакцию(ТранзакцияАктивнаНаНачалоВыполнения, НазваниеОбработчика)
ИмяСобытия = СобытиеЖурналаРегистрации() + "." + НСтр("ru = 'Выполнение обработчиков'", ОбщегоНазначения.КодОсновногоЯзыка());
Если ТранзакцияАктивнаНаНачалоВыполнения Тогда
Если ТранзакцияАктивна() Тогда
// Проверка поглощенных исключений в обработчиках.
Попытка
Константы.ИспользоватьРазделениеПоОбластямДанных.Получить();
Исключение
ШаблонКомментария = НСтр("ru = 'Ошибка выполнения обработчика обновления %1:
|Обработчиком обновления было поглощено исключение при активной внешней транзакции.
|При активных транзакциях, открытых выше по стеку, исключение также необходимо пробрасывать выше по стеку.'");
Комментарий = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонКомментария, НазваниеОбработчика);
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка,,, Комментарий);
ВызватьИсключение(Комментарий);
КонецПопытки;
Иначе
ШаблонКомментария = НСтр("ru = 'Ошибка выполнения обработчика обновления %1:
|Обработчиком обновления была закрыта лишняя транзакция, открытая ранее (выше по стеку).'");
Комментарий = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонКомментария, НазваниеОбработчика);
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка,,, Комментарий);
ВызватьИсключение(Комментарий);
КонецЕсли;
Иначе
Если ТранзакцияАктивна() Тогда
ШаблонКомментария = НСтр("ru = 'Ошибка выполнения обработчика обновления %1:
|Открытая внутри обработчика обновления транзакция осталась активной (не была закрыта или отменена).'");
Комментарий = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонКомментария, НазваниеОбработчика);
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка,,, Комментарий);
ВызватьИсключение(Комментарий);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура ПроверитьСвойстваОбработчиков(ИтерацияОбновления)
Для каждого Обработчик Из ИтерацияОбновления.Обработчики Цикл
ОписаниеОшибки = "";
Если ПустаяСтрока(Обработчик.Версия) Тогда
Если Обработчик.НачальноеЗаполнение <> Истина Тогда
ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'У обработчика не заполнено свойство %1 или свойство %2.'"),
"Версия", "НачальноеЗаполнение");
КонецЕсли;
ИначеЕсли Обработчик.Версия <> "*"
И Не СтрНачинаетсяС(Обработчик.Версия, "ОтладкаОбработчика") Тогда
Попытка
НулеваяВерсия = ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Обработчик.Версия, "0.0.0.0") = 0;
Исключение
НулеваяВерсия = Ложь;
ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'У обработчика неправильно заполнено свойство %1: ""%2"".
|Правильный формат, например: ""2.1.3.70"".'"),
"Версия", Обработчик.Версия);
КонецПопытки;
Если НулеваяВерсия Тогда
ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'У обработчика неправильно заполнено свойство %1: ""%2"".
|Версия не может быть нулевой.'"),
"Версия", Обработчик.Версия);
КонецЕсли;
Если НЕ ЗначениеЗаполнено(ОписаниеОшибки)
И Обработчик.ВыполнятьВГруппеОбязательных <> Истина
И Обработчик.Приоритет <> 0 Тогда
ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'У обработчика неправильно заполнено свойство %1 или
|свойство %2.'"),
"Приоритет", "ВыполнятьВГруппеОбязательных");
КонецЕсли;
КонецЕсли;
Если Обработчик.РежимВыполнения <> ""
И Обработчик.РежимВыполнения <> "Монопольно"
И Обработчик.РежимВыполнения <> "Оперативно"
И Обработчик.РежимВыполнения <> "Отложенно" Тогда
ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'У обработчика ""%1"" неправильно заполнено свойство %2.
|Допустимое значение: ""%3"", ""%4"", ""%5"".'"),
Обработчик.Процедура, "РежимВыполнения", "Монопольно", "Отложенно", "Оперативно");
КонецЕсли;
Если НЕ ЗначениеЗаполнено(ОписаниеОшибки)
И Обработчик.Опциональный = Истина
И Обработчик.НачальноеЗаполнение = Истина Тогда
ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'У обработчика не правильно заполнено свойство %1 или
|свойство %2.'"),
"Опциональный", "НачальноеЗаполнение");
КонецЕсли;
Если Не ЗначениеЗаполнено(ОписаниеОшибки) Тогда
Продолжить;
КонецЕсли;
Если ИтерацияОбновления.ЭтоОсновнаяКонфигурация Тогда
ЗаголовокОшибки = НСтр("ru = 'Ошибка в свойстве обработчика обновления конфигурации'");
Иначе
ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Ошибка в свойстве обработчика обновления библиотеки %1 версии %2'"),
ИтерацияОбновления.Подсистема,
ИтерацияОбновления.Версия);
КонецЕсли;
ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
ЗаголовокОшибки + Символы.ПС
+ НСтр("ru = '(%1).'") + Символы.ПС
+ Символы.ПС
+ ОписаниеОшибки,
Обработчик.Процедура);
ЗаписатьОшибку(ОписаниеОшибки);
ВызватьИсключение ОписаниеОшибки;
КонецЦикла;
КонецПроцедуры
Функция КоличествоОбработчиковНаТекущуюВерсию(ИтерацииОбновления, РежимВыполненияОтложенногоОбновления)
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Отложенно);
Запрос.УстановитьПараметр("РежимВыполненияОтложенногоОбработчика", Перечисления.РежимыВыполненияОтложенныхОбработчиков.Параллельно);
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.ИмяОбработчика КАК ИмяОбработчика
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.РежимВыполнения <> &РежимВыполнения";
КоличествоРазделенныхОбработчиков = Запрос.Выполнить().Выгрузить().Количество();
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновленияОбщихДанных.ИмяОбработчика КАК ИмяОбработчика
|ИЗ
| РегистрСведений.ОбработчикиОбновленияОбщихДанных КАК ОбработчикиОбновленияОбщихДанных";
КоличествоНеразделенныхОбработчиков = Запрос.Выполнить().Выгрузить().Количество();
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.ИмяОбработчика КАК ИмяОбработчика
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.РежимВыполнения = &РежимВыполнения";
КоличествоОтложенныхОбработчиков = Запрос.Выполнить().Выгрузить().Количество();
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.ИмяОбработчика КАК ИмяОбработчика
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.РежимВыполненияОтложенногоОбработчика = &РежимВыполненияОтложенногоОбработчика";
КоличествоПроцедурРегистрации = Запрос.Выполнить().Выгрузить().Количество();
КоличествоОбработчиков = КоличествоРазделенныхОбработчиков + КоличествоНеразделенныхОбработчиков + КоличествоПроцедурРегистрации;
Если РежимВыполненияОтложенногоОбновления = "Монопольно" Тогда
КоличествоОбработчиков = КоличествоОбработчиков + КоличествоОтложенныхОбработчиков;
КонецЕсли;
Возврат Новый Структура("ВсегоОбработчиков, ВыполненоОбработчиков", КоличествоОбработчиков, 0);
КонецФункции
Функция ИмяОбъектаМетаданныхПоИмениМенеджера(ИмяМенеджера)
Позиция = СтрНайти(ИмяМенеджера, ".");
Если Позиция = 0 Тогда
Возврат "ОбщийМодуль." + ИмяМенеджера;
КонецЕсли;
ТипМенеджера = Лев(ИмяМенеджера, Позиция - 1);
ИменаТипов = Новый Соответствие;
ИменаТипов.Вставить("Справочники", "Справочник");
ИменаТипов.Вставить("Документы", "Документ");
ИменаТипов.Вставить("Обработки", "Обработка");
ИменаТипов.Вставить("ПланыВидовХарактеристик", "ПланВидовХарактеристик");
ИменаТипов.Вставить("РегистрыБухгалтерии", "РегистрБухгалтерии");
ИменаТипов.Вставить("РегистрыНакопления", "РегистрНакопления");
ИменаТипов.Вставить("РегистрыРасчета", "РегистрРасчета");
ИменаТипов.Вставить("РегистрыСведений", "РегистрСведений");
ИменаТипов.Вставить("БизнесПроцессы", "БизнесПроцесс");
ИменаТипов.Вставить("ЖурналыДокументов", "ЖурналДокументов");
ИменаТипов.Вставить("Задачи", "Задача");
ИменаТипов.Вставить("Отчеты", "Отчет");
ИменаТипов.Вставить("Константы", "Константа");
ИменаТипов.Вставить("Перечисления", "Перечисление");
ИменаТипов.Вставить("ПланыВидовРасчета", "ПланВидовРасчета");
ИменаТипов.Вставить("ПланыОбмена", "ПланОбмена");
ИменаТипов.Вставить("ПланыСчетов", "ПланСчетов");
ИмяТипа = ИменаТипов[ТипМенеджера];
Если ИмяТипа = Неопределено Тогда
Возврат ИмяМенеджера;
КонецЕсли;
Возврат ИмяТипа + Сред(ИмяМенеджера, Позиция);
КонецФункции
Процедура ОтметитьОбработчикиНовыхПодсистем(ВсеОбработчики)
// Список объектов новых подсистем.
ОбъектыНовыхПодсистем = Новый Массив;
Для Каждого ИмяПодсистемы Из СведенияОбОбновленииИнформационнойБазы().НовыеПодсистемы Цикл
Подсистема = Метаданные.НайтиПоПолномуИмени(ИмяПодсистемы);
Если Подсистема = Неопределено Тогда
Продолжить;
КонецЕсли;
Для Каждого ОбъектМетаданных Из Подсистема.Состав Цикл
ОбъектыНовыхПодсистем.Добавить(ОбъектМетаданных.ПолноеИмя());
КонецЦикла;
КонецЦикла;
// Определение обработчиков новых подсистем.
ВсеОбработчики.Колонки.Добавить("ЭтоНоваяПодсистема", Новый ОписаниеТипов("Булево"));
Для Каждого ОписаниеОбработчика Из ВсеОбработчики Цикл
Позиция = СтрНайти(ОписаниеОбработчика.Процедура, ".", НаправлениеПоиска.СКонца);
ИмяМенеджера = Лев(ОписаниеОбработчика.Процедура, Позиция - 1);
Если ОбъектыНовыхПодсистем.Найти(ИмяОбъектаМетаданныхПоИмениМенеджера(ИмяМенеджера)) <> Неопределено Тогда
ОписаниеОбработчика.ЭтоНоваяПодсистема = Истина;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// См. СтандартныеПодсистемыСервер.ПриОтправкеДанныхПодчиненному.
Процедура ПриОтправкеВерсийПодсистем(ЭлементДанных, ОтправкаЭлемента, Знач СозданиеНачальногоОбраза = Ложь)
СтандартнаяОбработка = Истина;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ОбновлениеВерсииИБВМоделиСервиса") Тогда
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("ОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса");
МодульОбновлениеИнформационнойБазыСлужебныйВМоделиСервиса.ПриОтправкеВерсийПодсистем(ЭлементДанных, ОтправкаЭлемента,
СозданиеНачальногоОбраза, СтандартнаяОбработка);
КонецЕсли;
Если Не СтандартнаяОбработка Тогда
Возврат;
КонецЕсли;
Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Удалить
ИЛИ ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда
// Стандартную обработку не переопределяем.
ИначеЕсли ТипЗнч(ЭлементДанных) = Тип("РегистрСведенийНаборЗаписей.ВерсииПодсистем") Тогда
Если Не СозданиеНачальногоОбраза Тогда
// Выгрузку регистра выполняем только при создании начального образа.
ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Функция ОтметкаНачалаОбновления()
ОписаниеСеанса = Новый Структура;
ОписаниеСеанса.Вставить("ИмяКомпьютера");
ОписаниеСеанса.Вставить("ИмяПриложения");
ОписаниеСеанса.Вставить("НачалоСеанса");
ОписаниеСеанса.Вставить("НомерСеанса");
ОписаниеСеанса.Вставить("НомерСоединения");
ОписаниеСеанса.Вставить("Пользователь");
ЗаполнитьЗначенияСвойств(ОписаниеСеанса, ПолучитьТекущийСеансИнформационнойБазы());
Пользователь = ОписаниеСеанса.Пользователь; // ПользовательИнформационнойБазы
ОписаниеСеанса.Пользователь = Пользователь.Имя;
ИмяПараметра = "СтандартныеПодсистемы.ОбновлениеВерсииИБ.СеансОбновленияИнформационнойБазы";
МожноВыполнятьОбновление = Истина;
Блокировка = Новый БлокировкаДанных;
Если ОбщегоНазначения.РазделениеВключено()
И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
ЭлементБлокировки = Блокировка.Добавить("Константа.СведенияОбОбновленииИБ");
Иначе
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыПрограммы");
ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра);
КонецЕсли;
НачатьТранзакцию();
Попытка
Блокировка.Заблокировать();
СохраненныеПараметры = СведенияОСеансеОбновления(ИмяПараметра);
Если СохраненныеПараметры = Неопределено Тогда
СеансыСовпадают = Ложь;
Иначе
СеансыСовпадают = ДанныеСовпадают(ОписаниеСеанса, СохраненныеПараметры);
КонецЕсли;
Если Не СеансыСовпадают Тогда
СеансОбновленияАктивен = СеансАктивен(СохраненныеПараметры);
Если СеансОбновленияАктивен Тогда
СеансОбновления = СохраненныеПараметры;
МожноВыполнятьОбновление = Ложь;
Иначе
ЗаписатьСведенияОСеансеОбновления(ИмяПараметра, ОписаниеСеанса);
СеансОбновления = ОписаниеСеанса;
КонецЕсли;
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
Результат = Новый Структура;
Результат.Вставить("МожноВыполнятьОбновление", МожноВыполнятьОбновление);
Результат.Вставить("СеансОбновления", СеансОбновления);
Возврат Результат;
КонецФункции
Функция СведенияОСеансеОбновления(ИмяПараметра)
Если ОбщегоНазначения.РазделениеВключено()
И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Сведения = СведенияОбОбновленииИнформационнойБазы();
СеансОбновления = Сведения.СеансОбновления;
Иначе
СеансОбновления = СтандартныеПодсистемыСервер.ПараметрРаботыПрограммы(ИмяПараметра);
КонецЕсли;
Возврат СеансОбновления;
КонецФункции
Процедура ЗаписатьСведенияОСеансеОбновления(ИмяПараметра, ОписаниеСеанса)
Если ОбщегоНазначения.РазделениеВключено()
И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Сведения = СведенияОбОбновленииИнформационнойБазы();
Сведения.СеансОбновления = ОписаниеСеанса;
ЗаписатьСведенияОбОбновленииИнформационнойБазы(Сведения);
Иначе
СтандартныеПодсистемыСервер.УстановитьПараметрРаботыПрограммы(ИмяПараметра, ОписаниеСеанса);
КонецЕсли;
КонецПроцедуры
Функция СеансАктивен(ОписаниеСеанса)
Если ОписаниеСеанса = Неопределено Тогда
Возврат Ложь;
КонецЕсли;
СеансыИнформационнойБазы = ПолучитьСеансыИнформационнойБазы();
Для Каждого Сеанс Из СеансыИнформационнойБазы Цикл
Совпадают = ДанныеСовпадают(ОписаниеСеанса, Сеанс);
Если Совпадают Тогда
Прервать;
КонецЕсли;
КонецЦикла;
Возврат Совпадают;
КонецФункции
Функция ДанныеСовпадают(Данные1, Данные2)
Совпадают = Истина;
Для Каждого КлючИЗначение Из Данные1 Цикл
Если КлючИЗначение.Ключ = "Пользователь" Тогда
Продолжить;
КонецЕсли;
Если Данные2[КлючИЗначение.Ключ] <> КлючИЗначение.Значение Тогда
Совпадают = Ложь;
Прервать;
КонецЕсли;
КонецЦикла;
Возврат Совпадают;
КонецФункции
Функция НоваяТаблицаИнформацииОбОбработчиках() Экспорт
ИнфоОбработчиков = Новый ТаблицаЗначений;
ИнфоОбработчиков.Колонки.Добавить("ИмяОбработчика", Новый ОписаниеТипов("Строка"));
ИнфоОбработчиков.Колонки.Добавить("РежимВыполнения", Новый ОписаниеТипов("Строка"));
ИнфоОбработчиков.Колонки.Добавить("ИмяБиблиотеки", Новый ОписаниеТипов("Строка"));
ИнфоОбработчиков.Колонки.Добавить("Версия", Новый ОписаниеТипов("Строка"));
ИнфоОбработчиков.Колонки.Добавить("Статус", Новый ОписаниеТипов("Строка"));
ИнфоОбработчиков.Колонки.Добавить("ДлительностьОбработки", Новый ОписаниеТипов("Число"));
ИнфоОбработчиков.Колонки.Добавить("ИнформацияОбОшибке", Новый ОписаниеТипов("Строка"));
ИнфоОбработчиков.Колонки.Добавить("ОбластьДанных", Новый ОписаниеТипов("Число"));
Возврат ИнфоОбработчиков;
КонецФункции
Функция НовыйПрогрессОбновленияОбластейДанных() Экспорт
Прогресс = Новый Структура;
Прогресс.Вставить("Обновлено", 0);
Прогресс.Вставить("Выполняется", 0);
Прогресс.Вставить("Ожидают", 0);
Прогресс.Вставить("Проблемы", 0);
Прогресс.Вставить("ОбластиОбновлено", Новый Массив);
Прогресс.Вставить("ОбластиВыполняется", Новый Массив);
Прогресс.Вставить("ОбластиОжидает", Новый Массив);
Прогресс.Вставить("ОбластиСПроблемами", Новый Массив);
Возврат Прогресс;
КонецФункции
Функция ИменаПоЗначениямПеречисления(МетаданныеПеречисления) Экспорт
МенеджерПеречисления = Перечисления[МетаданныеПеречисления.Имя];
Результат = Новый Соответствие;
Для Каждого ЭлементКоллекции Из МетаданныеПеречисления.ЗначенияПеречисления Цикл // ОбъектМетаданных
Результат.Вставить(МенеджерПеречисления[ЭлементКоллекции.Имя], ЭлементКоллекции.Имя);
КонецЦикла;
Возврат Результат;
КонецФункции
Функция ЗначениеПеречисленияПоИмени(ИмяЗначения, МетаданныеПеречисления) Экспорт
МенеджерПеречисления = Перечисления[МетаданныеПеречисления.Имя];
Если Не ЗначениеЗаполнено(ИмяЗначения) Тогда
Возврат МенеджерПеречисления.ПустаяСсылка();
КонецЕсли;
Результат = Неопределено;
ДоступныеЗначения = Новый Массив;
ИмяЗначенияДляСравнения = ВРег(ИмяЗначения);
Для Каждого ЭлементКоллекции Из МетаданныеПеречисления.ЗначенияПеречисления Цикл // ОбъектМетаданных
Если ВРег(ЭлементКоллекции.Имя) = ИмяЗначенияДляСравнения Тогда
Результат = МенеджерПеречисления[ЭлементКоллекции.Имя];
Прервать;
КонецЕсли;
ДоступныеЗначения.Добавить("""" + ЭлементКоллекции.Имя + """");
КонецЦикла;
Если Результат = Неопределено Тогда
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Некорректное имя ""%1"" значения перечисления ""%2"".
|Доступные значения: %3'"), ИмяЗначения, МетаданныеПеречисления, СтрСоединить(ДоступныеЗначения, ", "));
КонецЕсли;
Возврат Результат;
КонецФункции
////////////////////////////////////////////////////////////////////////////////
// Протоколирование хода обновления.
Процедура ЗаписатьИнформацию(Знач Текст) Экспорт
ЖурналРегистрации.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Информация,,, Текст);
КонецПроцедуры
Процедура ЗаписатьОшибку(Знач Текст) Экспорт
ЖурналРегистрации.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Ошибка,,, Текст);
КонецПроцедуры
Процедура ЗаписатьПредупреждение(Знач Текст) Экспорт
ЖурналРегистрации.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Предупреждение,,, Текст);
КонецПроцедуры
Процедура ЗаписатьИнформациюОХодеОбновления(Обработчик, ХодВыполненияОбработчиков, ВФоне)
Если ХодВыполненияОбработчиков = Неопределено Тогда
Возврат;
КонецЕсли;
ХодВыполненияОбработчиков.ВыполненоОбработчиков = ХодВыполненияОбработчиков.ВыполненоОбработчиков + 1;
Если Не ОбщегоНазначения.РазделениеВключено() Тогда
Сообщение = НСтр("ru = 'Выполняется обработчик обновления %1 (%2 из %3).'");
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
Сообщение, Обработчик.Процедура,
ХодВыполненияОбработчиков.ВыполненоОбработчиков, ХодВыполненияОбработчиков.ВсегоОбработчиков);
ЗаписатьИнформацию(Сообщение);
КонецЕсли;
Если ВФоне Тогда
Прогресс = 10 + ХодВыполненияОбработчиков.ВыполненоОбработчиков / ХодВыполненияОбработчиков.ВсегоОбработчиков * 90;
ДлительныеОперации.СообщитьПрогресс(Прогресс);
КонецЕсли;
КонецПроцедуры
////////////////////////////////////////////////////////////////////////////////
// Описание обновлений
// Вывести описания изменений в указанной версии.
//
// Параметры:
// НомерВерсии - Строка - номер версии, для которого выводится описание из макета
// табличного документа МакетОписаниеОбновлений в табличный документ.
// ДокументОписаниеОбновлений.
//
Процедура ВывестиОписаниеИзменений(Знач НомерВерсии, ДокументОписаниеОбновлений, МакетОписаниеОбновлений)
Номер = СтрЗаменить(НомерВерсии, ".", "_");
Если МакетОписаниеОбновлений.Области.Найти("Шапка" + Номер) = Неопределено Тогда
Возврат;
КонецЕсли;
ДокументОписаниеОбновлений.Вывести(МакетОписаниеОбновлений.ПолучитьОбласть("Шапка" + Номер));
ДокументОписаниеОбновлений.НачатьГруппуСтрок("Версия" + Номер);
ДокументОписаниеОбновлений.Вывести(МакетОписаниеОбновлений.ПолучитьОбласть("Версия" + Номер));
ДокументОписаниеОбновлений.ЗакончитьГруппуСтрок();
ДокументОписаниеОбновлений.Вывести(МакетОписаниеОбновлений.ПолучитьОбласть("Отступ"));
КонецПроцедуры
Функция ПоследняяВерсияОтображенияИзмененийСистемы(Знач ИмяПользователя = Неопределено) Экспорт
Если ИмяПользователя = Неопределено Тогда
ИмяПользователя = ИмяПользователя();
КонецЕсли;
ПоследняяВерсия = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить("ОбновлениеИБ",
"ПоследняяВерсияОтображенияИзмененийСистемы", , , ИмяПользователя);
Возврат ПоследняяВерсия;
КонецФункции
Процедура ОпределитьВыводОписанияОбновлений(ВыводитьОписаниеОбновлений)
Если ВыводитьОписаниеОбновлений И Не ОбщегоНазначения.РазделениеВключено() Тогда
ОбщегоНазначения.ХранилищеОбщихНастроекСохранить("ОбновлениеИБ", "ВывестиОписаниеИзмененийДляАдминистратора", Истина, , ИмяПользователя());
КонецЕсли;
Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
СведенияОбОбновленииИБ = СведенияОбОбновленииИнформационнойБазы();
СведенияОбОбновленииИБ.ВыводитьОписаниеОбновлений = ВыводитьОписаниеОбновлений;
ЗаписатьСведенияОбОбновленииИнформационнойБазы(СведенияОбОбновленииИБ);
КонецЕсли;
КонецПроцедуры
// Возвращает список разделов описания изменений системы.
//
// Возвращаемое значение:
// СписокЗначений:
// * Значение - Число - вес версии.
// * Представление - Строка - версии.
//
Функция РазделыОписанияИзменений() Экспорт
Разделы = Новый СписокЗначений;
ВесВерсииМетаданных = ВесВерсии(Метаданные.Версия);
МакетОписаниеОбновлений = Метаданные.ОбщиеМакеты.Найти("ОписаниеИзмененийСистемы");
Если МакетОписаниеОбновлений <> Неопределено Тогда
ПредикатВерсии = "Версия";
ПредикатШапки = "Шапка";
Макет = ПолучитьОбщийМакет(МакетОписаниеОбновлений);
Для каждого Область Из Макет.Области Цикл
Если СтрНайти(Область.Имя, ПредикатВерсии) = 0 Тогда
Продолжить;
КонецЕсли;
ВерсияВФорматеОписания = Сред(Область.Имя, СтрДлина(ПредикатВерсии) + 1);
Если Макет.Области.Найти(ПредикатШапки + ВерсияВФорматеОписания) = Неопределено Тогда
Продолжить;
КонецЕсли;
РазрядыВерсииСтроками = СтрРазделить(ВерсияВФорматеОписания, "_");
Если РазрядыВерсииСтроками.Количество() <> 4 Тогда
Продолжить;
КонецЕсли;
ВесВерсии = ВесВерсииИзМассиваСтрок(РазрядыВерсииСтроками);
Версия = ""
+ Число(РазрядыВерсииСтроками[0]) + "."
+ Число(РазрядыВерсииСтроками[1]) + "."
+ Число(РазрядыВерсииСтроками[2]) + "."
+ Число(РазрядыВерсииСтроками[3]);
Если ВесВерсии > ВесВерсииМетаданных Тогда
ТекстИсключения = НСтр("ru = 'В общем макете %1 для одного из разделов изменений
|установлена версия выше, чем в метаданных. (%2, должна быть %3)'");
ТекстИсключения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстИсключения,
"ОписаниеИзмененийСистемы", Версия, Метаданные.Версия);
ВызватьИсключение ТекстИсключения;
КонецЕсли;
Разделы.Добавить(ВесВерсии, Версия);
КонецЦикла;
Разделы.СортироватьПоЗначению(НаправлениеСортировки.Убыв);
КонецЕсли;
Возврат Разделы;
КонецФункции
Функция ВесВерсииИзМассиваСтрок(РазрядыВерсииСтроками)
Возврат 0
+ Число(РазрядыВерсииСтроками[0]) * 1000000000
+ Число(РазрядыВерсииСтроками[1]) * 1000000
+ Число(РазрядыВерсииСтроками[2]) * 1000
+ Число(РазрядыВерсииСтроками[3]);
КонецФункции
Функция ПолучитьВерсииБольшеЗаданной(Разделы, Версия)
Результат = Новый Массив;
Если Разделы = Неопределено Тогда
Разделы = РазделыОписанияИзменений();
КонецЕсли;
ВесВерсии = ВесВерсии(Версия);
Для каждого ЭлементСписка Из Разделы Цикл
Если ЭлементСписка.Значение <= ВесВерсии Тогда
Продолжить;
КонецЕсли;
Результат.Добавить(ЭлементСписка.Представление);
КонецЦикла;
Возврат Результат;
КонецФункции
Процедура ОтключитьОтложенноеОбновление()
ПриВключенииОтложенногоОбновления(Ложь);
КонецПроцедуры
Функция ВыполненыВсеОтложенныеОбработчики(СведенияОбОбновлении)
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Отложенно);
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыОбработчиковОбновления.Выполнен);
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.ИмяОбработчика КАК ИмяОбработчика,
| ОбработчикиОбновления.Статус КАК Статус
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.РежимВыполнения = &РежимВыполнения
| И ОбработчикиОбновления.Статус <> &Статус";
НевыполненныеОбработчики = Запрос.Выполнить().Выгрузить();
Если НевыполненныеОбработчики.Количество() = 0 Тогда
СведенияОбОбновлении.ВремяОкончаниеОтложенногоОбновления = ТекущаяДатаСеанса();
СведенияОбОбновлении.ОтложенноеОбновлениеЗавершеноУспешно = Истина;
ЗаписатьСведенияОбОбновленииИнформационнойБазы(СведенияОбОбновлении);
Константы.ОтложенноеОбновлениеЗавершеноУспешно.Установить(Истина);
Если Не ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ() Тогда
Константы.ОтложенноеОбновлениеВГлавномУзлеЗавершеноУспешно.Установить(Истина);
КонецЕсли;
Возврат Истина;
Иначе
Возврат Ложь;
КонецЕсли;
КонецФункции
////////////////////////////////////////////////////////////////////////////////
// Вспомогательные процедуры и функции отложенного обновления.
Процедура ОбработчикПроверкиВеденияУчета(Проверка, ПараметрыПроверки) Экспорт
// Обработка не требуется, регистрация проблемных объектов выполняется
// из обработчиков обновления.
Возврат;
КонецПроцедуры
Функция КоличествоПроблемСДанными() Экспорт
Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтрольВеденияУчета") Тогда
Возврат 0;
КонецЕсли;
МодульКонтрольВеденияУчета = ОбщегоНазначения.ОбщийМодуль("КонтрольВеденияУчета");
Проверка = МодульКонтрольВеденияУчета.ПроверкаПоИдентификатору("ОбновлениеИнформационнойБазыПроблемаСДанными");
КоличествоПроблем = МодульКонтрольВеденияУчета.КоличествоПроблемПоПравилуПроверки(Проверка);
Возврат КоличествоПроблем;
КонецФункции
Процедура ОчиститьЗарегистрированныеПроблемыСДанными()
Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтрольВеденияУчета") Тогда
Возврат;
КонецЕсли;
Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Возврат;
КонецЕсли;
МодульКонтрольВеденияУчета = ОбщегоНазначения.ОбщийМодуль("КонтрольВеденияУчета");
Проверка = МодульКонтрольВеденияУчета.ПроверкаПоИдентификатору("ОбновлениеИнформационнойБазыПроблемаСДанными");
МодульКонтрольВеденияУчета.ОчиститьРезультатПоПроверке(Проверка);
КонецПроцедуры
// Только для внутреннего использования.
//
Функция ВыполнитьОтложенныйОбработчикОбновления(ПараметрыОбновления = Неопределено)
КонтекстОбработчика = НовыйКонтекстОбработчика();
ОбработчикОбновления = НайтиОбработчикОбновления(КонтекстОбработчика, ПараметрыОбновления);
Если ТипЗнч(ОбработчикОбновления) = Тип("СтрокаТаблицыЗначений") Тогда
АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено);
Попытка
ОбработчикВыполнилсяБезОшибок = Ложь;
Если ОбработчикОбновления.Многопоточный Тогда
ДополнитьКонтекстМногопоточногоОбработчика(КонтекстОбработчика);
ОбрабатываемыеДанные = ОбработчикОбновления.ОбрабатываемыеДанные.Получить();
ОбрабатываемыеДанные.ПоследняяВыбраннаяЗапись = Неопределено;
ОбрабатываемыеДанные.ПоискЗавершен = Ложь;
ПараметрыВыборки = ОбрабатываемыеДанные.ПараметрыВыборки;
ПроверитьПараметрыВыборки(ПараметрыВыборки);
ПараметрыВыборки.МаксимумВыборки = ОбновлениеИнформационнойБазы.МаксимальноеКоличествоЗаписейВВыборке();
ПараметрыПоиска = НовыеПараметрыПоискаПорции();
ПараметрыПоиска.ПараметрыВыборки = ПараметрыВыборки;
ПараметрыПоиска.ПоследняяВыбраннаяЗапись = ОбрабатываемыеДанные.ПоследняяВыбраннаяЗапись;
ПараметрыОбхода = ПараметрыОбходаДанныхДляОбновления(ПараметрыПоиска);
Очередь = КонтекстОбработчика.Параметры.Очередь;
ИтераторОбхода = ТекущиеПараметрыОбхода(ПараметрыОбхода);
ДополнительныеИсточникиДанных = ПараметрыВыборки.ДополнительныеИсточникиДанных;
Пока ИтераторОбхода <> Неопределено Цикл
ОбработчикВыполнилсяБезОшибок = Ложь;
СсылочныйОбъект = ИтераторОбхода.СсылочныйОбъект;
ТабличныйОбъект = ИтераторОбхода.ТабличныйОбъект;
НаборДанных = НовыйНаборДанныхДляОбновления();
ЗаписьДанных = НаборДанных.Добавить();
ПараметрыВыборки.ДополнительныеИсточникиДанных = ОбновлениеИнформационнойБазы.ИсточникиДанных(
ДополнительныеИсточникиДанных,
СсылочныйОбъект,
ТабличныйОбъект);
ЗаписьДанных.Данные = ВыбратьДанныеПорции(ПараметрыВыборки, Очередь, СсылочныйОбъект, ТабличныйОбъект);
ЗаписьДанных.СсылочныйОбъект = СсылочныйОбъект;
ЗаписьДанных.ТабличныйОбъект = ТабличныйОбъект;
ОбновляемыеДанные = НоваяПорцияДляОбновления();
ОбновляемыеДанные.НаборДанных = НаборДанных;
Если ЗаписьДанных.Данные.Количество() > 0 Тогда
ОбновляемыеДанные.ПерваяЗапись = КлючЗаписиПервойСтрокиНабораДанных(НаборДанных);
ОбновляемыеДанные.ПоследняяЗапись = КлючЗаписиПоследнейСтрокиНабораДанных(НаборДанных);
КонецЕсли;
КонтекстОбработчика.Параметры.ОбновляемыеДанные = ОбновляемыеДанные;
Количество = ЗаписьДанных.Данные.Количество();
Если КонтекстОбработчика.ВыполнитьОбработчик Тогда
ВыполнитьОтложенныйОбработчик(КонтекстОбработчика, АдресРезультата);
КонецЕсли;
ОбработчикВыполнилсяБезОшибок = Истина;
ЗавершитьВыполнениеОтложенногоОбработчика(КонтекстОбработчика, АдресРезультата);
Если Количество > 0 Тогда
ОбрабатываемыеДанные.ПоследняяВыбраннаяЗапись = КлючЗаписиПоследнейСтрокиНабораДанных(НаборДанных);
Иначе
ОбрабатываемыеДанные.ПоследняяВыбраннаяЗапись = Неопределено;
КонецЕсли;
СледующиеПараметрыОбхода(ПараметрыОбхода, Количество = ПараметрыВыборки.МаксимумВыборки);
ИтераторОбхода = ТекущиеПараметрыОбхода(ПараметрыОбхода);
КонецЦикла;
ПараметрыВыборки.ДополнительныеИсточникиДанных = ДополнительныеИсточникиДанных;
Иначе
Если КонтекстОбработчика.ВыполнитьОбработчик Тогда
ВыполнитьОтложенныйОбработчик(КонтекстОбработчика, АдресРезультата);
КонецЕсли;
ОбработчикВыполнилсяБезОшибок = Истина;
ЗавершитьВыполнениеОтложенногоОбработчика(КонтекстОбработчика, АдресРезультата);
КонецЕсли;
Исключение
ОбработатьИсключениеОбработчика(КонтекстОбработчика, ОбработчикОбновления, ИнформацияОбОшибке());
// Если обработчик вызвал исключение, то вызываем процедуру завершения обработчика.
Если Не ОбработчикВыполнилсяБезОшибок Тогда
КонтекстОбработчика.Вставить("ОбработкаИсключенияОбработчика");
ЗавершитьВыполнениеОтложенногоОбработчика(КонтекстОбработчика, АдресРезультата);
КонецЕсли;
КонецПопытки;
ИначеЕсли ОбработчикОбновления = Ложь Тогда
Возврат Ложь;
КонецЕсли;
Возврат Истина;
КонецФункции
// Завершить выполнение отложенного обработчика в основном потоке, после завершения работы фонового задания.
//
// Параметры:
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
//
Процедура ЗавершитьВыполнениеОтложенногоОбработчикаОбновления(КонтекстОбработчика)
ПараллельныйРежим = КонтекстОбработчика.ПараллельныйРежим;
ТекущаяИтерацияОбновления = КонтекстОбработчика.ТекущаяИтерацияОбновления;
ОбработчикОбновления = ОбработчикОбновления(КонтекстОбработчика.ИмяОбработчика);
УстанавливаемыеСвойства = Новый Структура;
Если ОбработчикОбновления.Статус = Перечисления.СтатусыОбработчиковОбновления.Выполнен Тогда
СведенияОБлокируемыхОбъектах = СведенияОБлокируемыхОбъектах();
СведенияОбОбработчике = СведенияОБлокируемыхОбъектах.Обработчики[ОбработчикОбновления.ИмяОбработчика];
Если СведенияОбОбработчике <> Неопределено Тогда
СведенияОбОбработчике.Выполнен = Истина;
ЗаписатьСведенияОБлокируемыхОбъектах(СведенияОБлокируемыхОбъектах);
КонецЕсли;
УстанавливаемыеСвойства.Вставить("ИнформацияОбОшибке", "");
ИначеЕсли ОбработчикОбновления.Статус = Перечисления.СтатусыОбработчиковОбновления.Выполняется Тогда
// Если у обработчика стоит высокий приоритет,
// то он вызывается пять раз, после чего вызывается следующий обработчик.
ЗапускиСПриоритетом = Неопределено;
Если ОбработчикОбновления.Приоритет = "ЖелательноБыстрее" Тогда
СтатистикаВыполнения = ОбработчикОбновления.СтатистикаВыполнения.Получить();
ЗапускиСПриоритетом = СтатистикаВыполнения["ЗапускиСПриоритетом"];
ЗапускиСПриоритетом = ?(ЗапускиСПриоритетом = Неопределено, 1, ?(ЗапускиСПриоритетом = 4, 0, ЗапускиСПриоритетом + 1));
СтатистикаВыполнения.Вставить("ЗапускиСПриоритетом", ЗапускиСПриоритетом);
УстанавливаемыеСвойства.Вставить("СтатистикаВыполнения", Новый ХранилищеЗначения(СтатистикаВыполнения));
КонецЕсли;
Если ЗапускиСПриоритетом = Неопределено Или ЗапускиСПриоритетом = 0 Тогда
УстанавливаемыеСвойства.Вставить("ИтерацияЗапуска", ТекущаяИтерацияОбновления);
КонецЕсли;
Иначе
УстанавливаемыеСвойства.Вставить("ИтерацияЗапуска", ТекущаяИтерацияОбновления);
КонецЕсли;
УстановитьСвойстваОбработчика(ОбработчикОбновления.ИмяОбработчика, УстанавливаемыеСвойства);
// В параллельном режиме обновление нужно останавливать, если обработчик не удалось выполнить,
// т.к. от данных, которые он обрабатывает, могут зависеть другие обработчики.
Если ПараллельныйРежим
И ОбработчикОбновления.Статус = Перечисления.СтатусыОбработчиковОбновления.Ошибка
И ОбработчикОбновления.ЧислоПопыток >= МаксимумПопытокОбновления(ОбработчикОбновления) Тогда
СведенияОбОбновлении = СведенияОбОбновленииИнформационнойБазы();
СведенияОбОбновлении.ВремяОкончаниеОтложенногоОбновления = ТекущаяДатаСеанса();
СведенияОбОбновлении.ОтложенноеОбновлениеЗавершеноУспешно = Ложь;
ЗаписатьСведенияОбОбновленииИнформационнойБазы(СведенияОбОбновлении);
Константы.ОтложенноеОбновлениеЗавершеноУспешно.Установить(Ложь);
Если Не ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ() Тогда
Константы.ОтложенноеОбновлениеВГлавномУзлеЗавершеноУспешно.Установить(Ложь);
КонецЕсли;
ШаблонОшибки = НСтр("ru = 'Не удалось выполнить обработчик обновления ""%1"". Подробнее в журнале регистрации.'");
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки,
КонтекстОбработчика.ИмяОбработчика);
КонтекстОбработчика.Вставить("ОшибкаПриЗавершенииОбработчика", ТекстОшибки);
КонецЕсли;
КонецПроцедуры
Функция ПереданныеПараметрыОбработчикаОбновления(Параметры)
ПереданныеПараметры = Новый Структура;
Для Каждого Параметр Из Параметры Цикл
Если Параметр.Ключ <> "ОбработкаЗавершена"
И Параметр.Ключ <> "ПрогрессВыполнения"
И Параметр.Ключ <> "Очередь"
И Параметр.Ключ <> "ОбновляемыеДанные" Тогда
ПереданныеПараметры.Вставить(Параметр.Ключ, Параметр.Значение);
КонецЕсли;
КонецЦикла;
Возврат ПереданныеПараметры;
КонецФункции
Функция НовыеСведенияОбОбновлении(СтарыеСведения = Неопределено)
СведенияОбОбновлении = Новый Структура;
СведенияОбОбновлении.Вставить("ВремяНачалаОбновления");
СведенияОбОбновлении.Вставить("ВремяОкончанияОбновления");
СведенияОбОбновлении.Вставить("ПродолжительностьОбновления");
СведенияОбОбновлении.Вставить("ВремяНачалаОтложенногоОбновления");
СведенияОбОбновлении.Вставить("ВремяОкончаниеОтложенногоОбновления");
СведенияОбОбновлении.Вставить("НомерСеанса", Новый СписокЗначений());
СведенияОбОбновлении.Вставить("ОтложенноеОбновлениеЗавершеноУспешно");
СведенияОбОбновлении.Вставить("ДеревоОбработчиков", Новый ДеревоЗначений());
СведенияОбОбновлении.Вставить("ВерсияДереваОбработчиков", "");
СведенияОбОбновлении.Вставить("ВыводитьОписаниеОбновлений", Ложь);
СведенияОбОбновлении.Вставить("ЛегальнаяВерсия", "");
СведенияОбОбновлении.Вставить("НовыеПодсистемы", Новый Массив);
СведенияОбОбновлении.Вставить("ВсеНовыеПодсистемы", Новый Массив);
СведенияОбОбновлении.Вставить("УправлениеОтложеннымОбновлением", Новый Структура);
СведенияОбОбновлении.Вставить("ТекущаяИтерацияОбновления", 1);
СведенияОбОбновлении.Вставить("СеансОбновления");
СведенияОбОбновлении.Вставить("ВерсияУдалениеПатчей");
СведенияОбОбновлении.Вставить("ЗависимостьГруппОбработчиков", Новый Соответствие);
СведенияОбОбновлении.Вставить("ВерсииПодсистемНаНачалоОбновления", Новый Соответствие);
СведенияОбОбновлении.Вставить("ДатаНачалаСеансаОбновления", Неопределено);
Если ТипЗнч(СтарыеСведения) = Тип("Структура") Тогда
ЗаполнитьЗначенияСвойств(СведенияОбОбновлении, СтарыеСведения);
КонецЕсли;
Возврат СведенияОбОбновлении;
КонецФункции
Функция РежимВыполненияОтложенногоОбновления(ПараметрыОбновления)
ИнформационнаяБазаФайловая = ОбщегоНазначения.ИнформационнаяБазаФайловая();
РазделениеВключено = ОбщегоНазначения.РазделениеВключено();
ДоступноИспользованиеРазделенныхДанных = ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных();
ВыполнятьОтложенныеОбработчики = ПараметрыОбновления.ВыполнятьОтложенныеОбработчики;
ПараметрЗапускаКлиента = ПараметрыСеанса.ПараметрыКлиентаНаСервере.Получить("ПараметрЗапуска");
Если Не РазделениеВключено Или ДоступноИспользованиеРазделенныхДанных Тогда
Если ИнформационнаяБазаФайловая
Или СтрНайти(НРег(ПараметрЗапускаКлиента), НРег("ВыполнитьОтложенноеОбновлениеСейчас")) > 0
Или ВыполнятьОтложенныеОбработчики Тогда
Возврат "Монопольно";
Иначе
Возврат "Отложенно";
КонецЕсли;
Иначе
Возврат Неопределено;
КонецЕсли;
КонецФункции
// Получает сведения об обновлении информационной базы из константы "СведенияОбОбновленииИБ".
//
Функция СведенияОБлокируемыхОбъектах() Экспорт
УстановитьПривилегированныйРежим(Истина);
Если ОбщегоНазначения.РазделениеВключено()
И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Возврат НовыеСведенияОБлокируемыхОбъектах();
КонецЕсли;
СведенияОБлокируемыхОбъектах = Константы.СведенияОБлокируемыхОбъектах.Получить().Получить();
Если ТипЗнч(СведенияОБлокируемыхОбъектах) <> Тип("Структура") Тогда
Возврат НовыеСведенияОБлокируемыхОбъектах();
КонецЕсли;
СведенияОБлокируемыхОбъектах = НовыеСведенияОБлокируемыхОбъектах(СведенияОБлокируемыхОбъектах);
Возврат СведенияОБлокируемыхОбъектах;
КонецФункции
// Подготовка запуска обработчика обновления в основном потоке.
//
// Параметры:
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
// ОбработчикОбновления - СтрокаДереваЗначений - обработчик обновления в виде строки дерева обработчиков.
// ПараметрыОбновления - см. ВыполнитьОбновлениеИнформационнойБазы
// СведенияОбОбновлении - см. СведенияОбОбновленииИнформационнойБазы
//
Процедура ПередЗапускомПроцедурыОбработкиДанных(КонтекстОбработчика,
ОбработчикОбновления,
ПараметрыОбновления,
СведенияОбОбновлении)
КонтекстОбработчика.ЗаписыватьВЖурнал = Константы.ДетализироватьОбновлениеИБВЖурналеРегистрации.Получить();
КонтекстОбработчика.ТранзакцияАктивнаНаНачалоВыполнения = ТранзакцияАктивна();
Попытка
ИмяОбработчика = ОбработчикОбновления.ИмяОбработчика;
ВерсииПодсистемНаНачалоОбновления = СведенияОбОбновлении.ВерсииПодсистемНаНачалоОбновления;
ВерсияПодсистемыНаНачалоОбновления = ВерсииПодсистемНаНачалоОбновления[ОбработчикОбновления.ИмяБиблиотеки];
КонтекстОбработчика.ЗапускВыполненБезОшибок = Истина;
СообщениеОЗапущенномОбработчике = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Выполняется процедура обновления ""%1"".'"), ИмяОбработчика);
ЖурналРегистрации.ДобавитьСообщениеДляЖурналаРегистрации(СобытиеЖурналаРегистрации(),
УровеньЖурналаРегистрации.Информация,,, СообщениеОЗапущенномОбработчике);
// Прогресс выполнения процедуры обработки данных.
ПрогрессВыполнения = Новый Структура;
ПрогрессВыполнения.Вставить("ВсегоОбъектов", 0);
ПрогрессВыполнения.Вставить("ОбработаноОбъектов", 0);
СтатистикаВыполнения = ОбработчикОбновления.СтатистикаВыполнения.Получить();
Если СтатистикаВыполнения["ПрогрессВыполнения"] <> Неопределено
И ТипЗнч(СтатистикаВыполнения["ПрогрессВыполнения"]) = Тип("Структура") Тогда
ЗаполнитьЗначенияСвойств(ПрогрессВыполнения, СтатистикаВыполнения["ПрогрессВыполнения"]);
КонецЕсли;
// Инициализация параметров обработчика.
Параметры = СтатистикаВыполнения["ПараметрыОбработчика"];
Если Параметры = Неопределено Тогда
Параметры = Новый Структура;
КонецЕсли;
КонтекстОбработчика.Параметры = Параметры;
Если ПараметрыОбновления.ПараллельныйРежим Тогда
Параметры.Вставить("ОбработкаЗавершена", Неопределено);
Иначе
Параметры.Вставить("ОбработкаЗавершена", Истина);
КонецЕсли;
Параметры.Вставить("ИмяОбработчика", ИмяОбработчика);
Параметры.Вставить("ПрогрессВыполнения", ПрогрессВыполнения);
Параметры.Вставить("ВерсияПодсистемыНаНачалоОбновления", ВерсияПодсистемыНаНачалоОбновления);
Параметры.Вставить("Очередь", ОбработчикОбновления.ОчередьОтложеннойОбработки);
Если КонтекстОбработчика.ЗаписыватьВЖурнал Тогда
КонтекстОбработчика.ДетальноеОписаниеОбработчика = ПодготовитьДетальнуюИнформациюОХодеОбновления(ОбработчикОбновления,
Параметры,
ОбработчикОбновления.ИмяБиблиотеки,
Истина);
КонецЕсли;
КоличествоЗапусковПроцедурыОбновления = КоличествоЗапусковПроцедурыОбновления(СтатистикаВыполнения);
ЧислоПотоковОбновления = КоличествоПотоковОбновленияИнформационнойБазы();
МаксимальноеКоличествоЗапусков = ЧислоПотоковОбновления * 10000;
Если КоличествоЗапусковПроцедурыОбновления > МаксимальноеКоличествоЗапусков Тогда // Защита от зацикливания.
Если ПараметрыОбновления.ПараллельныйРежим
И ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ()
И ПараметрыОбновления.ЕстьОбработчикиГлавногоУзла Тогда
ТекстОшибки = НСтр("ru = 'Превышено допустимое количество запусков процедуры обновления.
|Убедитесь, что дополнительные процедуры обработки данных в главном узле
|полностью завершились, выполните синхронизацию данных и повторно
|запустите выполнение процедур обработки данных в данном узле.'");
Иначе
ТекстОшибки = НСтр("ru = 'Превышено допустимое количество запусков процедуры обновления.
|Выполнение прервано для предотвращения зацикливания механизма обработки данных.'");
КонецЕсли;
МинимальнаяОчередь = МинимальнаяОчередьОтложеннойОбработки();
Если Не ПараметрыОбновления.ПараллельныйРежим
Или МинимальнаяОчередь = ОбработчикОбновления.ОчередьОтложеннойОбработки Тогда
ЧислоПопыток = МаксимумПопытокОбновления(ОбработчикОбновления);
УстановитьСвойствоОбработчика(ОбработчикОбновления.ИмяОбработчика, "ЧислоПопыток", ЧислоПопыток);
ВызватьИсключение ТекстОшибки;
КонецЕсли;
КонецЕсли;
// Запуск отложенного обработчика обновления.
Если СтатистикаВыполнения["НачалоОбработкиДанных"] = Неопределено Тогда
СтатистикаВыполнения.Вставить("НачалоОбработкиДанных", ТекущаяДатаСеанса());
КонецЕсли;
Свойства = Новый Структура;
Свойства.Вставить("Статус", Перечисления.СтатусыОбработчиковОбновления.Выполняется);
Свойства.Вставить("ОбработкаПорцииЗавершена", Ложь);
Свойства.Вставить("СтатистикаВыполнения", Новый ХранилищеЗначения(СтатистикаВыполнения));
УстановитьСвойстваОбработчика(ОбработчикОбновления.ИмяОбработчика, Свойства);
КонтекстОбработчика.НачалоОбработкиДанных = ТекущаяУниверсальнаяДатаВМиллисекундах();
Если ПараметрыОбновления.ПараллельныйРежим
И ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ()
И ОбработчикОбновления.ЗапускатьТолькоВГлавномУзле Тогда
// В подчиненном узле РИБ только проверяем, что обрабатываемые обработчиком данные
// пришли из главного узла и обновляем статус обработчика.
КонтекстОбработчика.ПропуститьПроверкуОбработанныхДанных = Истина;
ОписаниеОбрабатываемыхДанных = ОбработчикОбновления.ОбрабатываемыеДанные.Получить();
ДанныеОбработчика = ОписаниеОбрабатываемыхДанных.ДанныеОбработчика;
Если ДанныеОбработчика.Количество() = 0 Тогда
Параметры.ОбработкаЗавершена = Истина;
Иначе
Для Каждого ОбрабатываемыйОбъект Из ДанныеОбработчика Цикл
Параметры.ОбработкаЗавершена = ОбновлениеИнформационнойБазы.ОбработкаДанныхЗавершена(
ОбработчикОбновления.ОчередьОтложеннойОбработки,
ОбрабатываемыйОбъект.Ключ);
Если Не Параметры.ОбработкаЗавершена Тогда
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Иначе
КонтекстОбработчика.ВыполнитьОбработчик = Истина;
Возврат;
КонецЕсли;
Исключение
ОбработатьИсключениеОбработчика(КонтекстОбработчика, ОбработчикОбновления, ИнформацияОбОшибке());
КонтекстОбработчика.ЗапускВыполненБезОшибок = Ложь;
КонецПопытки;
ЗавершитьПроцедуруОбработкиДанных(КонтекстОбработчика, ОбработчикОбновления.ИмяОбработчика);
КонецПроцедуры
// Завершение запуска процедуры обработки данных в основном потоке.
//
// Параметры:
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
// ИмяОбработчика - Строка
//
Процедура ПослеЗапускаПроцедурыОбработкиДанных(КонтекстОбработчика, ИмяОбработчика)
ОбработчикОбновления = ОбработчикОбновления(ИмяОбработчика);
Параметры = КонтекстОбработчика.Параметры;
ПараметрыОбновления = КонтекстОбработчика.ПараметрыОбновления;
УстанавливаемыеСвойства = Новый Структура;
Попытка
ЗавершениеОбработкиДанных = ТекущаяУниверсальнаяДатаВМиллисекундах();
Если Параметры.ОбработкаЗавершена = Неопределено Тогда
ТекстОшибки = НСтр("ru = 'Обработчик обновления не инициализировал параметр %1.
|Выполнение прервано из-за явной ошибки в коде обработчика.'");
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки, "ОбработкаЗавершена");
ВызватьИсключение ТекстОшибки;
КонецЕсли;
СтатистикаВыполнения = ОбработчикОбновления.СтатистикаВыполнения.Получить();
ДобавитьКоличествоЗапусков = Истина;
Если Параметры.ОбработкаЗавершена
И Не КонтекстОбработчика.Свойство("ОбработкаИсключенияОбработчика") Тогда
СтатистикаВыполнения.Вставить("ЗавершениеОбработкиДанных", ТекущаяДатаСеанса());
УстанавливаемыеСвойства.Вставить("Статус", Перечисления.СтатусыОбработчиковОбновления.Выполнен);
УстанавливаемыеСвойства.Вставить("Приоритет","ВПлановомПорядке");
// Запись прогресса обновления.
Если ПараметрыОбновления.Свойство("ВФоне")
И ПараметрыОбновления.ВФоне Тогда
ХодВыполненияОбработчиков = ПараметрыОбновления.ХодВыполненияОбработчиков;
ХодВыполненияОбработчиков.ВыполненоОбработчиков = ХодВыполненияОбработчиков.ВыполненоОбработчиков + 1;
Прогресс = 10 + ХодВыполненияОбработчиков.ВыполненоОбработчиков / ХодВыполненияОбработчиков.ВсегоОбработчиков * 90;
ДлительныеОперации.СообщитьПрогресс(Прогресс);
КонецЕсли;
ИначеЕсли ПараметрыОбновления.ПараллельныйРежим И Не КонтекстОбработчика.ПропуститьПроверкуОбработанныхДанных Тогда
ЕстьОбработанныеОбъекты = ПараметрыСеанса.ПараметрыОбработчикаОбновления.ЕстьОбработанныеОбъекты;
ОчередьОбработчика = ОбработчикОбновления.ОчередьОтложеннойОбработки;
МинимальнаяОчередь = 0;
Если Не ЕстьОбработанныеОбъекты Тогда
МинимальнаяОчередь = МинимальнаяОчередьОтложеннойОбработки();
КонецЕсли;
ДобавитьКоличествоЗапусков = (ЕстьОбработанныеОбъекты Или ОчередьОбработчика = МинимальнаяОчередь);
Если Не ЕстьОбработанныеОбъекты
И ОчередьОбработчика = МинимальнаяОчередь Тогда
ЧислоПопыток = ОбработчикОбновления.ЧислоПопыток;
МаксимумПопыток = МаксимумПопытокОбновления(ОбработчикОбновления) - 1;
Если ЧислоПопыток >= МаксимумПопыток Тогда
ТекстИсключения = НСтр("ru = 'Произошло зацикливание процедуры обработки данных. Выполнение прервано.'");
ВызватьИсключение ТекстИсключения;
Иначе
ДобавляемоеЧислоПопыток = ДобавляемоеЧислоПопыток(ОбработчикОбновления, КонтекстОбработчика);
УстанавливаемыеСвойства.Вставить("ЧислоПопыток", ЧислоПопыток + ДобавляемоеЧислоПопыток);
КонецЕсли;
Иначе
УстанавливаемыеСвойства.Вставить("ЧислоПопыток", 0);
КонецЕсли;
КонецЕсли;
// Сохранение данных по процедуре обработки данных.
Если ОбработчикОбновления.Многопоточный Тогда
ПрогрессВыполнения = СтатистикаВыполнения["ПрогрессВыполнения"];
Если ПрогрессВыполнения = Неопределено Тогда
СтатистикаВыполнения.Вставить("ПрогрессВыполнения", Параметры.ПрогрессВыполнения);
Иначе
ОбработаноОбъектов = Параметры.ПрогрессВыполнения.ОбработаноОбъектов;
ПрогрессВыполнения.ОбработаноОбъектов = ПрогрессВыполнения.ОбработаноОбъектов + ОбработаноОбъектов;
КонецЕсли;
Иначе
СтатистикаВыполнения.Вставить("ПрогрессВыполнения", Параметры.ПрогрессВыполнения);
КонецЕсли;
Если ДобавитьКоличествоЗапусков Тогда
КоличествоЗапусковПроцедурыОбновления = КоличествоЗапусковПроцедурыОбновления(СтатистикаВыполнения) + 1;
Иначе
КоличествоЗапусковПроцедурыОбновления = КоличествоЗапусковПроцедурыОбновления(СтатистикаВыполнения);
КонецЕсли;
ДлительностьВыполнения = ЗавершениеОбработкиДанных - КонтекстОбработчика.НачалоОбработкиДанных;
Если СтатистикаВыполнения["ДлительностьВыполнения"] <> Неопределено Тогда
ДлительностьВыполнения = ДлительностьВыполнения + СтатистикаВыполнения["ДлительностьВыполнения"];
КонецЕсли;
СтатистикаВыполнения.Вставить("ДлительностьВыполнения", ДлительностьВыполнения);
СтатистикаВыполнения.Вставить("КоличествоЗапусков", КоличествоЗапусковПроцедурыОбновления);
УстанавливаемыеСвойства.Вставить("СтатистикаВыполнения", Новый ХранилищеЗначения(СтатистикаВыполнения));
УстанавливаемыеСвойства.Вставить("ДлительностьОбработки", ДлительностьВыполнения);
УстановитьСвойстваОбработчика(ОбработчикОбновления.ИмяОбработчика, УстанавливаемыеСвойства);
Исключение
ОбработатьИсключениеОбработчика(КонтекстОбработчика, ОбработчикОбновления, ИнформацияОбОшибке());
КонецПопытки;
КонецПроцедуры
// Завершение процедуры обработки данных.
//
// Параметры:
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
// ИмяОбработчика - Строка
//
Процедура ЗавершитьПроцедуруОбработкиДанных(КонтекстОбработчика, ИмяОбработчика)
ОбработчикОбновления = ОбработчикОбновления(ИмяОбработчика);
Параметры = КонтекстОбработчика.Параметры;
// Если обработчик обновления передал параметры, их нужно сохранить.
ПереданныеПараметры = ПереданныеПараметрыОбработчикаОбновления(Параметры);
СтатистикаВыполнения = ОбработчикОбновления.СтатистикаВыполнения.Получить();
СтатистикаВыполнения.Вставить("ПараметрыОбработчика", ПереданныеПараметры);
УстановитьСвойствоОбработчика(ОбработчикОбновления.ИмяОбработчика,
"СтатистикаВыполнения",
Новый ХранилищеЗначения(СтатистикаВыполнения));
Если КонтекстОбработчика.ЕстьНеЗакрытыеТранзакции Тогда
// В случае нахождения вложенной транзакции обработчик обновления повторно не вызывается.
ОбработчикОбновления.Статус = Перечисления.СтатусыОбработчиковОбновления.Ошибка;
ОбработчикОбновления.ИнформацияОбОшибке = Строка(ОбработчикОбновления.ИнформацияОбОшибке)
+ Символы.ПС + КонтекстОбработчика.ИнформацияОбОшибке;
ОбработчикОбновления.ЧислоПопыток = МаксимумПопытокОбновления(ОбработчикОбновления);
Свойства = Новый Структура;
Свойства.Вставить("ЧислоПопыток", ОбработчикОбновления.ЧислоПопыток);
Свойства.Вставить("Статус", ОбработчикОбновления.Статус);
Свойства.Вставить("ИнформацияОбОшибке", ОбработчикОбновления.ИнформацияОбОшибке);
УстановитьСвойстваОбработчика(ОбработчикОбновления.ИмяОбработчика, Свойства);
КонецЕсли;
Если КонтекстОбработчика.ЗаписыватьВЖурнал Тогда
ЗаписатьДетальнуюИнформациюОХодеОбновления(КонтекстОбработчика.ДетальноеОписаниеОбработчика);
КонецЕсли;
КонецПроцедуры
Процедура ЗаполнитьБлокируемыеОбъекты(СтрокаВерсия, СведенияОБлокируемыхОбъектах)
Для Каждого Обработчик Из СтрокаВерсия.Строки Цикл
ПроцедураПроверки = Обработчик.ПроцедураПроверки;
БлокируемыеОбъекты = Обработчик.БлокируемыеОбъекты;
Если ЗначениеЗаполнено(ПроцедураПроверки) И ЗначениеЗаполнено(БлокируемыеОбъекты) Тогда
СвойстваОбработчика = Новый Структура;
СвойстваОбработчика.Вставить("Выполнен", Ложь);
СвойстваОбработчика.Вставить("ПроцедураПроверки", ПроцедураПроверки);
СведенияОБлокируемыхОбъектах.Обработчики.Вставить(Обработчик.ИмяОбработчика, СвойстваОбработчика);
МассивБлокируемыхОбъектов = СтрРазделить(БлокируемыеОбъекты, ",");
Для Каждого БлокируемыйОбъект Из МассивБлокируемыхОбъектов Цикл
БлокируемыйОбъект = СтрЗаменить(СокрЛП(БлокируемыйОбъект), ".", "");
ИнформацияОбОбъекте = СведенияОБлокируемыхОбъектах.БлокируемыеОбъекты[БлокируемыйОбъект];
Если ИнформацияОбОбъекте = Неопределено Тогда
МассивОбработчиков = Новый Массив;
МассивОбработчиков.Добавить(Обработчик.ИмяОбработчика);
СведенияОБлокируемыхОбъектах.БлокируемыеОбъекты.Вставить(БлокируемыйОбъект, МассивОбработчиков);
Иначе
СведенияОБлокируемомОбъекте = СведенияОБлокируемыхОбъектах.БлокируемыеОбъекты[БлокируемыйОбъект]; // Массив
СведенияОБлокируемомОбъекте.Добавить(Обработчик.ИмяОбработчика);
КонецЕсли;
КонецЦикла;
ИначеЕсли ЗначениеЗаполнено(БлокируемыеОбъекты) И Не ЗначениеЗаполнено(ПроцедураПроверки) Тогда
ТекстИсключения = НСтр("ru = 'У отложенного обработчика обновления ""%1""
|заполнен список блокируемых объектов, но не задано свойство ""%2"".'");
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстИсключения, Обработчик.ИмяОбработчика, "ПроцедураПроверки");
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Функция НовыеСведенияОБлокируемыхОбъектах(СтарыеСведения = Неопределено)
СведенияОБлокируемыхОбъектах = Новый Структура;
СведенияОБлокируемыхОбъектах.Вставить("БлокируемыеОбъекты", Новый Соответствие);
СведенияОБлокируемыхОбъектах.Вставить("Обработчики", Новый Соответствие);
СведенияОБлокируемыхОбъектах.Вставить("РазблокированныеОбъекты", Новый Соответствие);
Если ТипЗнч(СтарыеСведения) = Тип("Структура") Тогда
ЗаполнитьЗначенияСвойств(СведенияОБлокируемыхОбъектах, СтарыеСведения);
КонецЕсли;
Возврат СведенияОБлокируемыхОбъектах;
КонецФункции
Процедура ЗаписатьСведенияОБлокируемыхОбъектах(Сведения) Экспорт
Если Сведения = Неопределено Тогда
НовоеЗначение = НовыеСведенияОБлокируемыхОбъектах();
Иначе
НовоеЗначение = Сведения;
КонецЕсли;
МенеджерКонстанты = Константы.СведенияОБлокируемыхОбъектах.СоздатьМенеджерЗначения();
МенеджерКонстанты.Значение = Новый ХранилищеЗначения(НовоеЗначение);
ОбновлениеИнформационнойБазы.ЗаписатьДанные(МенеджерКонстанты);
КонецПроцедуры
Процедура ЗаполнитьДанныеДляПараллельногоОтложенногоОбновления(Параметры) Экспорт
Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
ОтметитьРегистрациюОтложенныхОбработчиковОбновления();
Возврат;
КонецЕсли;
Если Параметры.ПриЗапускеКлиентскогоПриложения
И Параметры.РежимВыполненияОтложенногоОбновления = "Отложенно" Тогда
КлиентСервер = Не ОбщегоНазначения.ИнформационнаяБазаФайловая();
Коробка = Не ОбщегоНазначения.РазделениеВключено();
Если КлиентСервер И Коробка Тогда
// Регистрация данных выполняется позже.
Возврат;
КонецЕсли;
КонецЕсли;
ПерезапускОбновления = Параметры.Свойство("ПерезапускОбновления");
РегистрируемыеОбработчики = Новый Массив;
Если Параметры.Свойство("РегистрируемыеОбработчики") Тогда
РегистрируемыеОбработчики = Параметры.РегистрируемыеОбработчики;
КонецЕсли;
УдалитьВсеПотокиОбновления();
Если Не (СтандартныеПодсистемыПовтИсп.ИспользуетсяРИБ("СФильтром") И ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ()) И Не ПерезапускОбновления Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОбновлениеИнформационнойБазы.Ссылка КАК Узел
|ИЗ
| ПланОбмена.ОбновлениеИнформационнойБазы КАК ОбновлениеИнформационнойБазы
|ГДЕ
| НЕ ОбновлениеИнформационнойБазы.ЭтотУзел";
Выгрузка = Запрос.Выполнить().Выгрузить();
УзлыОбмена = Выгрузка.ВыгрузитьКолонку("Узел");
Для Каждого ЭлементСостава Из Метаданные.ПланыОбмена.ОбновлениеИнформационнойБазы.Состав Цикл
ПланыОбмена.УдалитьРегистрациюИзменений(УзлыОбмена, ЭлементСостава.Метаданные);
КонецЦикла;
КонецЕсли;
Если Не ОбщегоНазначения.ЭтоПодчиненныйУзелРИБ()
И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда
МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер");
МодульОбменДаннымиСервер.СброситьЗначениеКонстантыСИзменениямиДляПодчиненногоУзлаРИБСФильтрами();
КонецЕсли;
ПараметрыИнициализированы = Ложь;
Обработчики = ОбработчикиДляОтложеннойРегистрацииДанных(Ложь, ПерезапускОбновления, РегистрируемыеОбработчики);
Для Каждого Обработчик Из Обработчики Цикл
Если Не ПараметрыИнициализированы Тогда
ПараметрыОбработчикаСтруктура = ОбновлениеИнформационнойБазы.ОсновныеПараметрыОтметкиКОбработке();
ПараметрыИнициализированы = Истина;
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда
МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер");
МодульОбменДаннымиСервер.ИнициализироватьФайлСДаннымиОбновления(ПараметрыОбработчикаСтруктура);
КонецЕсли;
КонецЕсли;
ПараметрыОбработчикаСтруктура.Очередь = Обработчик.ОчередьОтложеннойОбработки;
ПараметрыОбработчикаСтруктура.ИмяОбработчика = Обработчик.ИмяОбработчика;
ПараметрыОбработчикаСтруктура.Вставить("ДанныеОбработчика", Новый Соответствие);
ПараметрыОбработчикаСтруктура.Вставить("ПерезапускОбновления", ПерезапускОбновления);
Если Обработчик.Многопоточный Тогда
ПараметрыОбработчикаСтруктура.ПараметрыВыборки =
ОбновлениеИнформационнойБазы.ДополнительныеПараметрыВыборкиДанныхДляМногопоточнойОбработки();
Иначе
ПараметрыОбработчикаСтруктура.ПараметрыВыборки = Неопределено;
КонецЕсли;
ПараметрыОбработчика = Новый Массив;
ПараметрыОбработчика.Добавить(ПараметрыОбработчикаСтруктура);
Попытка
Сообщение = НСтр("ru = 'Выполняется процедура заполнения данных
|""%1""
|отложенного обработчика обновления
|""%2"".'");
Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Сообщение,
Обработчик.ПроцедураЗаполненияДанныхОбновления,
Обработчик.ИмяОбработчика);
ЗаписатьИнформацию(Сообщение);
ОбщегоНазначения.ВыполнитьМетодКонфигурации(Обработчик.ПроцедураЗаполненияДанныхОбновления, ПараметрыОбработчика);
Если Обработчик.Многопоточный Тогда
ИсправитьПолныеИменаВПараметрахВыборки(ПараметрыОбработчикаСтруктура.ПараметрыВыборки);
КонецЕсли;
// Запись прогресса обновления.
Если Не ПерезапускОбновления И Параметры.ВФоне Тогда
ХодВыполненияОбработчиков = Параметры.ХодВыполненияОбработчиков;
ХодВыполненияОбработчиков.ВыполненоОбработчиков = ХодВыполненияОбработчиков.ВыполненоОбработчиков + 1;
Прогресс = 10 + ХодВыполненияОбработчиков.ВыполненоОбработчиков / ХодВыполненияОбработчиков.ВсегоОбработчиков * 90;
ДлительныеОперации.СообщитьПрогресс(Прогресс);
КонецЕсли;
Исключение
Если Не ПерезапускОбновления Тогда
ОтметитьРегистрациюОтложенныхОбработчиковОбновления(Обработчик.ИмяБиблиотеки, Ложь);
КонецЕсли;
ЗаписатьОшибку(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'При вызове процедуры заполнения данных
|""%1""
|отложенного обработчика обновления
|""%2""
|произошла ошибка:
|""%3"".'"),
Обработчик.ПроцедураЗаполненияДанныхОбновления,
Обработчик.ИмяОбработчика,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
ВызватьИсключение;
КонецПопытки;
ОписаниеОбрабатываемыхДанных = НовоеОписаниеОбрабатываемыхДанных(Обработчик.Многопоточный);
ОписаниеОбрабатываемыхДанных.ДанныеОбработчика = ПараметрыОбработчикаСтруктура.ДанныеОбработчика;
ОписаниеОбрабатываемыхДанных.ИмяОбработчика = Обработчик.ИмяОбработчика;
Если Обработчик.Многопоточный Тогда
ОписаниеОбрабатываемыхДанных.ПараметрыВыборки = ПараметрыОбработчикаСтруктура.ПараметрыВыборки;
КонецЕсли;
ОписаниеОбрабатываемыхДанных = Новый ХранилищеЗначения(ОписаниеОбрабатываемыхДанных, Новый СжатиеДанных(9));
УстановитьСвойствоОбработчика(Обработчик.ИмяОбработчика, "ОбрабатываемыеДанные", ОписаниеОбрабатываемыхДанных);
КонецЦикла;
Если Не ПерезапускОбновления Тогда
ОтметитьРегистрациюОтложенныхОбработчиковОбновления();
КонецЕсли;
Если ПараметрыИнициализированы И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными") Тогда
МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер");
МодульОбменДаннымиСервер.ЗавершитьЗаписьФайлаСДаннымиОбновления(ПараметрыОбработчикаСтруктура);
КонецЕсли;
КонецПроцедуры
// Заполнить данные для параллельного отложенного обновления в фоне, используя несколько потоков.
//
// Параметры:
// ИдентификаторФормы - УникальныйИдентификатор - идентификатор формы, отображающей процесс обновления.
// АдресРезультата - Строка - адрес временного хранилища с результатом выполнения процедуры.
//
Процедура ЗапускРегистрацииДанныхОтложенногоОбновления(ИдентификаторФормы, АдресРезультата) Экспорт
Группы = НовоеОписаниеГруппПотоковРегистрацииДанныхОтложенногоОбновления();
Обработчики = ОбработчикиДляОтложеннойРегистрацииДанных();
УдалитьВсеПотокиОбновления();
Попытка
ДоступнаПакетнаяРегистрация = ОбновлениеИнформационнойБазы.ДоступнаПакетнаяРегистрация();
Если ДоступнаПакетнаяРегистрация Тогда
ТекущаяОчередь = ?(Обработчики.Количество() > 0, Обработчики[0].ОчередьОтложеннойОбработки, 0);
КонецЕсли;
Для Каждого Обработчик Из Обработчики Цикл
Если ДоступнаПакетнаяРегистрация И Обработчик.ОчередьОтложеннойОбработки > ТекущаяОчередь Тогда
ОжидатьЗавершениеВсехПотоков(Группы);
ТекущаяОчередь = Обработчик.ОчередьОтложеннойОбработки;
КонецЕсли;
ОписаниеОбрабатываемыхДанных = Обработчик.ОбрабатываемыеДанные.Получить();
Поток = ДобавитьПотокРегистрацииДанныхОтложенногоОбновления(ОписаниеОбрабатываемыхДанных);
ВыполнитьПоток(Группы, Поток, ИдентификаторФормы);
ОжидатьСвободныйПоток(Группы);
КонецЦикла;
ОжидатьЗавершениеВсехПотоков(Группы);
УдалитьВсеПотокиОбновления();
Исключение
ОтменитьВыполнениеВсехПотоков(Группы);
УдалитьВсеПотокиОбновления();
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
// Заполнение данных отложенного обработчика в фоновом задании.
//
// Параметры:
// ОписаниеОбрабатываемыхДанных - см. НовоеОписаниеОбрабатываемыхДанных
// АдресРезультата - Строка - адрес временного хранилища для сохранения результата выполнения процедуры.
//
Процедура ЗаполнитьДанныеОтложенногоОбработчика(ОписаниеОбрабатываемыхДанных, АдресРезультата) Экспорт
ПараметрыОтметкиКОбработке = ОбновлениеИнформационнойБазы.ОсновныеПараметрыОтметкиКОбработке();
ЕстьПодсистемаОбменаДанными = ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОбменДанными");
Если ЕстьПодсистемаОбменаДанными Тогда
МодульОбменДаннымиСервер = ОбщегоНазначения.ОбщийМодуль("ОбменДаннымиСервер");
МодульОбменДаннымиСервер.ИнициализироватьФайлСДаннымиОбновления(ПараметрыОтметкиКОбработке);
КонецЕсли;
ПараметрыОтметкиКОбработке.Очередь = ОписаниеОбрабатываемыхДанных.Очередь;
ПараметрыОтметкиКОбработке.ИмяОбработчика = ОписаниеОбрабатываемыхДанных.ИмяОбработчика;
ПараметрыОтметкиКОбработке.Вставить("ДанныеОбработчика", Новый Соответствие);
МногопоточныйРежим = ЭтоОписаниеДанныхМногопоточногоОбработчика(ОписаниеОбрабатываемыхДанных);
Если МногопоточныйРежим Тогда
ПараметрыОтметкиКОбработке.ПараметрыВыборки =
ОбновлениеИнформационнойБазы.ДополнительныеПараметрыВыборкиДанныхДляМногопоточнойОбработки();
Иначе
ПараметрыОтметкиКОбработке.ПараметрыВыборки = Неопределено;
КонецЕсли;
ПараметрыОбработчика = Новый Массив;
ПараметрыОбработчика.Добавить(ПараметрыОтметкиКОбработке);
ШаблонСообщения = НСтр(
"ru = 'Выполняется процедура заполнения данных
|""%1""
|отложенного обработчика обновления
|""%2"".'");
ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения,
ОписаниеОбрабатываемыхДанных.ПроцедураЗаполнения,
ОписаниеОбрабатываемыхДанных.ИмяОбработчика);
ЗаписатьИнформацию(ТекстСообщения);
Попытка
ОбщегоНазначения.ВыполнитьМетодКонфигурации(ОписаниеОбрабатываемыхДанных.ПроцедураЗаполнения, ПараметрыОбработчика);
Исключение
ИнформацияОбОшибке = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
ШаблонОшибки = НСтр(
"ru = 'При вызове процедуры заполнения данных
|""%1""
|отложенного обработчика обновления
|""%2""
|произошла ошибка:
|""%3"".'");
ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки,
ОписаниеОбрабатываемыхДанных.ПроцедураЗаполнения,
ОписаниеОбрабатываемыхДанных.ИмяОбработчика,
ИнформацияОбОшибке);
ЗаписатьОшибку(ТекстСообщения);
ВызватьИсключение;
КонецПопытки;
Результат = Новый Структура;
Результат.Вставить("ДанныеОбработчика", ПараметрыОтметкиКОбработке.ДанныеОбработчика);
Если МногопоточныйРежим Тогда
Результат.Вставить("ПараметрыВыборки", ПараметрыОтметкиКОбработке.ПараметрыВыборки);
КонецЕсли;
Если ЕстьПодсистемаОбменаДанными Тогда
ДанныеОбновления = МодульОбменДаннымиСервер.ЗавершитьЗаписьФайлаИПолучитьДанныеОбновления(ПараметрыОтметкиКОбработке);
Результат.Вставить("ДанныеОбновления", ДанныеОбновления);
Результат.Вставить("ИмяФайлаСИзменениями", ПараметрыОтметкиКОбработке.ИмяФайлаСИзменениями);
КонецЕсли;
ПоместитьВоВременноеХранилище(Результат, АдресРезультата);
КонецПроцедуры
Процедура УстановитьПараметрыОбработчикаОбновления(ОбработчикОбновления, Отложенно = Ложь, Параллельно = Ложь)
Если ОбработчикОбновления = Неопределено Тогда
ПараметрыСеанса.ПараметрыОбработчикаОбновления = Новый ФиксированнаяСтруктура(НовыеПараметрыОбработчикаОбновления());
Возврат;
КонецЕсли;
Если Отложенно Тогда
РежимВыполнения = "Отложенно";
ИмяОбработчика = ОбработчикОбновления.ИмяОбработчика;
Иначе
РежимВыполнения = "Монопольно";
ИмяОбработчика = ОбработчикОбновления.Процедура;
КонецЕсли;
Если Параллельно Тогда
РежимВыполненияОтложенныхОбработчиков = "Параллельно";
Иначе
РежимВыполненияОтложенныхОбработчиков = "Последовательно";
КонецЕсли;
ПолучениеСвойств = Новый Структура;
ПолучениеСвойств.Вставить("ИзменяемыеОбъекты", "");
ЗаполнитьЗначенияСвойств(ПолучениеСвойств, ОбработчикОбновления);
ПараметрыОбработчикаОбновления = НовыеПараметрыОбработчикаОбновления();
ПараметрыОбработчикаОбновления.ЗапускатьТолькоВГлавномУзле = ОбработчикОбновления.ЗапускатьТолькоВГлавномУзле;
ПараметрыОбработчикаОбновления.ЗапускатьИВПодчиненномУзлеРИБСФильтрами = ОбработчикОбновления.ЗапускатьИВПодчиненномУзлеРИБСФильтрами;
ПараметрыОбработчикаОбновления.ОчередьОтложеннойОбработки = ОбработчикОбновления.ОчередьОтложеннойОбработки;
ПараметрыОбработчикаОбновления.РежимВыполнения = РежимВыполнения;
ПараметрыОбработчикаОбновления.РежимВыполненияОтложенныхОбработчиков = РежимВыполненияОтложенныхОбработчиков;
ПараметрыОбработчикаОбновления.КлючЗаписиПрогрессаОбновления = Новый УникальныйИдентификатор;
ПараметрыОбработчикаОбновления.ЕстьОбработанныеОбъекты = Ложь;
ПараметрыОбработчикаОбновления.ИмяОбработчика = ИмяОбработчика;
ПараметрыОбработчикаОбновления.ИзменяемыеОбъекты = УникальныеЗначенияЧерезЗапятую(ПолучениеСвойств.ИзменяемыеОбъекты);
ПараметрыСеанса.ПараметрыОбработчикаОбновления = Новый ФиксированнаяСтруктура(ПараметрыОбработчикаОбновления);
КонецПроцедуры
Функция НовыеПараметрыОбработчикаОбновления() Экспорт
ПараметрыОбработчикаОбновления = Новый Структура;
ПараметрыОбработчикаОбновления.Вставить("ЗапускатьТолькоВГлавномУзле", Ложь);
ПараметрыОбработчикаОбновления.Вставить("ЗапускатьИВПодчиненномУзлеРИБСФильтрами", Ложь);
ПараметрыОбработчикаОбновления.Вставить("ОчередьОтложеннойОбработки", 0);
ПараметрыОбработчикаОбновления.Вставить("РежимВыполнения", "");
ПараметрыОбработчикаОбновления.Вставить("РежимВыполненияОтложенныхОбработчиков", "");
ПараметрыОбработчикаОбновления.Вставить("ЕстьОбработанныеОбъекты", Ложь);
ПараметрыОбработчикаОбновления.Вставить("КлючЗаписиПрогрессаОбновления", Неопределено);
ПараметрыОбработчикаОбновления.Вставить("ИмяОбработчика", "");
ПараметрыОбработчикаОбновления.Вставить("ИзменяемыеОбъекты", "");
Возврат ПараметрыОбработчикаОбновления;
КонецФункции
// Обработать исключение, возникшее при подготовке или завершении выполнения обработчика в основном потоке.
//
// Параметры:
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
// ОбработчикОбновления - СтрокаДереваЗначений - обработчик обновления в виде строки дерева обработчиков.
//
Процедура ОбработатьИсключениеОбработчика(КонтекстОбработчика, ОбработчикОбновления, ИнформацияОбОшибке)
Если КонтекстОбработчика.ЗаписыватьВЖурнал Тогда
ЗаписатьДетальнуюИнформациюОХодеОбновления(КонтекстОбработчика.ДетальноеОписаниеОбработчика);
КонецЕсли;
// АПК:325-выкл откат незакрытых транзакций после выполнения обработчика.
Если Не КонтекстОбработчика.Свойство("ПропуститьОтменуТранзакций") Тогда
Пока ТранзакцияАктивна() Цикл
ОтменитьТранзакцию();
КонецЦикла;
КонецЕсли;
// АПК:325-вкл
ДобавляемоеЧислоПопыток = ДобавляемоеЧислоПопыток(ОбработчикОбновления, КонтекстОбработчика, Истина);
ЧислоПопыток = ОбработчикОбновления.ЧислоПопыток + ДобавляемоеЧислоПопыток;
ПодробноеПредставлениеОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке);
МаксимумПопытокОбновления = МаксимумПопытокОбновления(ОбработчикОбновления);
Если ЧислоПопыток < МаксимумПопытокОбновления Тогда
ЗаписатьПредупреждение(ПодробноеПредставлениеОшибки);
Иначе
ОбновлениеИнформационнойБазы.ЗаписатьСобытиеВЖурналРегистрации(ПодробноеПредставлениеОшибки, , КонтекстОбработчика.Параметры);
КонецЕсли;
Свойства = Новый Структура;
Свойства.Вставить("ЧислоПопыток", ЧислоПопыток);
Свойства.Вставить("Статус", Перечисления.СтатусыОбработчиковОбновления.Ошибка);
Свойства.Вставить("ИнформацияОбОшибке", ПодробноеПредставлениеОшибки);
УстановитьСвойстваОбработчика(ОбработчикОбновления.ИмяОбработчика, Свойства);
КонецПроцедуры
// Обработать СуществующиеПоставляемыеЭлементы, полученный в результате разбиения результата поиска данных для
// обновления, в отдельном потоке.
//
// Параметры:
// СуществующиеПоставляемыеЭлементы - Массив из см. НовыйНаборПорцийДляОбновления
// ОписаниеПотоков - см. НовоеОписаниеПотоков
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
//
Процедура ОбработатьФрагментДанныхВПотоке(Фрагмент, Группы, КонтекстОбработчика)
КонтекстОбработчикаДляПотока = ОбщегоНазначения.СкопироватьРекурсивно(КонтекстОбработчика); // см. НовыйКонтекстОбработчика
КонтекстОбработчикаДляПотока.Параметры.ОбновляемыеДанные = Фрагмент;
Поток = НовыйПоток();
ДобавитьПотокОбработчикаОбновления(Поток, КонтекстОбработчикаДляПотока);
ВыполнитьПоток(Группы, Поток);
КонтекстОбработчикаДляПотока.Параметры.ОбновляемыеДанные.НаборДанных = Неопределено;
КонецПроцедуры
// Устанавливает статус ошибки у всех зациклившихся обработчиков.
//
Процедура ОтметитьЗациклившиесяОбработчики()
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Отложенно);
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыОбработчиковОбновления.Выполняется);
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.ИмяОбработчика КАК ИмяОбработчика,
| ОбработчикиОбновления.Статус КАК Статус,
| ОбработчикиОбновления.ЧислоПопыток КАК ЧислоПопыток,
| ОбработчикиОбновления.Многопоточный,
| ОбработчикиОбновления.ОбрабатываемыеДанные
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.РежимВыполнения = &РежимВыполнения
| И ОбработчикиОбновления.Статус = &Статус";
Выполняющиеся = Запрос.Выполнить().Выгрузить();
Для каждого ОбработчикОбновления Из Выполняющиеся Цикл
МаксимумПопыток = МаксимумПопытокОбновления(ОбработчикОбновления) - 1;
Если ОбработчикОбновления.ЧислоПопыток >= МаксимумПопыток Тогда
ИнформацияОбОшибке = НСтр("ru = 'Произошло зацикливание процедуры обработки данных. Выполнение прервано.'");
УстановитьСтатусОбработчика(ОбработчикОбновления.ИмяОбработчика, "Ошибка", ИнформацияОбОшибке);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// Проверяет, все ли выполняемые обработчики зациклились.
// Условия зацикливания:
// - все выполняющиеся обработчики имеют число попыток >= 2;
// - или
// - есть минимум один выполняющийся обработчик с числом попыток >= 2
// - и
// - есть минимум один обработчик, завершенный с ошибкой.
//
// Возвращаемое значение:
// Булево - Истина, если обработчики зациклились.
//
Функция ВсеОбработчикиЗациклились()
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Отложенно);
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыОбработчиковОбновления.Выполняется);
Запрос.Текст =
"ВЫБРАТЬ
| ОбработчикиОбновления.ИмяОбработчика КАК ИмяОбработчика,
| ОбработчикиОбновления.Многопоточный КАК Многопоточный,
| ОбработчикиОбновления.ОбрабатываемыеДанные КАК ОбрабатываемыеДанные,
| ОбработчикиОбновления.Статус КАК Статус,
| ОбработчикиОбновления.ЧислоПопыток КАК ЧислоПопыток
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.РежимВыполнения = &РежимВыполнения
| И ОбработчикиОбновления.Статус = &Статус";
Выполняющиеся = Запрос.Выполнить().Выгрузить();
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Отложенно);
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыОбработчиковОбновления.Ошибка);
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ИСТИНА
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.РежимВыполнения = &РежимВыполнения
| И ОбработчикиОбновления.Статус = &Статус";
СОшибками = Запрос.Выполнить().Выгрузить();
Если Выполняющиеся.Количество() > 0 Тогда
ЕстьПревысившие = Ложь;
ЕстьНормальные = Ложь;
Для каждого ОбработчикОбновления Из Выполняющиеся Цикл
МаксимумПопыток = МаксимумПопытокОбновления(ОбработчикОбновления) - 1;
Если ОбработчикОбновления.ЧислоПопыток < МаксимумПопыток Тогда
ЕстьНормальные = Истина;
Иначе
ЕстьПревысившие = Истина;
КонецЕсли;
Если ЕстьНормальные И ЕстьПревысившие Тогда
Прервать;
КонецЕсли;
КонецЦикла;
Если ЕстьПревысившие Тогда
Если ЕстьНормальные Тогда
Возврат СОшибками.Количество() > 0;
Иначе
Возврат Истина;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Возврат Ложь;
КонецФункции
// Получить количество запусков процедуры обновления.
//
// Параметры:
// ОбработчикОбновления - СтрокаДереваЗначений - обработчик обновления в виде строки дерева обработчиков.
//
// Возвращаемое значение:
// Число - количество запусков.
//
Функция КоличествоЗапусковПроцедурыОбновления(СтатистикаВыполнения)
КоличествоЗапусковПроцедурыОбновления = СтатистикаВыполнения["КоличествоЗапусков"];
Если КоличествоЗапусковПроцедурыОбновления = Неопределено Тогда
КоличествоЗапусковПроцедурыОбновления = 0;
КонецЕсли;
Возврат КоличествоЗапусковПроцедурыОбновления;
КонецФункции
// Возвращает максимальное количество попыток обновления для указанного обработчика обновления.
//
// Параметры:
// ОбработчикОбновления - СтрокаТаблицыЗначений - обработчик обновления в виде строки дерева обработчиков.
//
// Возвращаемое значение:
// Число - максимальное количество попыток обновления.
//
Функция МаксимумПопытокОбновления(ОбработчикОбновления)
Если ОбработчикОбновления.Многопоточный Тогда
ОбрабатываемыеДанные = ОбработчикОбновления.ОбрабатываемыеДанные.Получить();
ПараметрыВыборки = ОбрабатываемыеДанные.ПараметрыВыборки;
ПолныеИменаОбъектов = ПараметрыВыборки.ПолныеИменаОбъектов;
ПолныеИменаРегистров = ПараметрыВыборки.ПолныеИменаРегистров;
СоставОбъектов = СтрРазделить(ПолныеИменаОбъектов, ",");
СоставРегистров = СтрРазделить(ПолныеИменаРегистров, ",");
КоличествоПотоков = КоличествоПотоковОбновленияИнформационнойБазы();
Множитель = СоставОбъектов.Количество() * СоставРегистров.Количество() + КоличествоПотоков;
Иначе
Множитель = 1;
КонецЕсли;
Возврат 3 * Множитель;
КонецФункции
// Количество добавляемых попыток для счетчика ЧислоПопыток.
//
// Параметры:
// ОбработчикОбновления - СтрокаДереваЗначений - обработчик обновления в виде строки дерева обработчиков.
// КонтекстОбработчика - см. НовыйКонтекстОбработчика
// Ошибка - Булево - Истина, если в обработчике обновления возникла ошибка.
//
// Возвращаемое значение:
// Число - 0, если это многопоточный обработчик, которому не были переданы данные для обновления, иначе 1.
//
Функция ДобавляемоеЧислоПопыток(ОбработчикОбновления, КонтекстОбработчика, Ошибка = Ложь)
Если ОбработчикОбновления.Многопоточный Тогда
Если КонтекстОбработчика.Параметры.Свойство("ОбновляемыеДанные") Тогда
ОбновляемыеДанные = КонтекстОбработчика.Параметры.ОбновляемыеДанные;
Иначе
ОбновляемыеДанные = Неопределено;
КонецЕсли;
// Проверяется по полям ОбновляемыеДанные.ПерваяЗапись и ОбновляемыеДанные.ПоследняяЗапись, а не по полю
// ОбновляемыеДанные.НаборДанных, т.к. оно очищается в ОбработатьФрагментДанныхВПотоке() для экономии памяти.
// ОбновляемыеДанные может быть Неопределено, если обработчик выбросил исключение.
Если ОбновляемыеДанные <> Неопределено Тогда
ЕстьДанные = ОбновляемыеДанные.ПерваяЗапись <> Неопределено Или ОбновляемыеДанные.ПоследняяЗапись <> Неопределено;
Если Не ЕстьДанные И Не Ошибка Тогда
Возврат 0;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Возврат 1;
КонецФункции
Функция МинимальнаяОчередьОтложеннойОбработки()
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("РежимВыполнения", Перечисления.РежимыВыполненияОбработчиков.Отложенно);
Запрос.УстановитьПараметр("Статус", Перечисления.СтатусыОбработчиковОбновления.Выполнен);
Запрос.УстановитьПараметр("РежимВыполненияОтложенногоОбработчика", Перечисления.РежимыВыполненияОтложенныхОбработчиков.Параллельно);
Запрос.Текст =
"ВЫБРАТЬ
| МИНИМУМ(ОбработчикиОбновления.ОчередьОтложеннойОбработки) КАК Очередь
|ИЗ
| РегистрСведений.ОбработчикиОбновления КАК ОбработчикиОбновления
|ГДЕ
| ОбработчикиОбновления.РежимВыполнения = &РежимВыполнения
| И ОбработчикиОбновления.РежимВыполненияОтложенногоОбработчика = &РежимВыполненияОтложенногоОбработчика
| И ОбработчикиОбновления.Статус <> &Статус";
Результат = Запрос.Выполнить().Выгрузить();
Возврат Результат[0].Очередь;
КонецФункции
Функция ОстатокМассива(Массив, ЗначениеНачала)
ОстатокМассива = Новый Массив;
ТочноеЗначениеНачала = СокрЛП(ЗначениеНачала);
ЗначениеНайдено = Ложь;
Для Каждого Элемент Из СтрРазделитьСокрЛП(Массив, ",") Цикл
Если ТочноеЗначениеНачала = Элемент Тогда
ЗначениеНайдено = Истина;
КонецЕсли;
Если ЗначениеНайдено Тогда
ОстатокМассива.Добавить(Элемент);
КонецЕсли;
КонецЦикла;
Возврат ОстатокМассива;
КонецФункции
// Исправить перечисленные через запятую полные имена объектов и регистров
// с помощью УникальныеЗначенияЧерезЗапятую, чтобы не сбивалась курсорная выборка данных.
//
// Параметры:
// ПараметрыВыборки - см. ОбновлениеИнформационнойБазы.ДополнительныеПараметрыВыборкиДанныхДляМногопоточнойОбработки
//
Процедура ИсправитьПолныеИменаВПараметрахВыборки(ПараметрыВыборки)
ПараметрыВыборки.ПолныеИменаОбъектов = УникальныеЗначенияЧерезЗапятую(ПараметрыВыборки.ПолныеИменаОбъектов);
ПараметрыВыборки.ПолныеИменаРегистров = УникальныеЗначенияЧерезЗапятую(ПараметрыВыборки.ПолныеИменаРегистров);
КонецПроцедуры
// Оставить только уникальные значения, перечисленные через запятую и упорядочить их.
//
// Параметры:
// Строка - Строка - значения, перечисленные через запятую.
//
// Возвращаемое значение:
// Строка - только уникальные упорядоченные значения через запятую.
//
Функция УникальныеЗначенияЧерезЗапятую(Строка)
Если Строка = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
Значения = СтрРазделить(Строка, ",");
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Значение");
Для Каждого Значение Из Значения Цикл
ТочноеЗначение = СокрЛП(Значение);
Если Не ПустаяСтрока(ТочноеЗначение) Тогда
СтрокаТаблицы = Таблица.Добавить();
СтрокаТаблицы.Значение = ТочноеЗначение;
КонецЕсли;
КонецЦикла;
Таблица.Свернуть("Значение");
Таблица.Сортировать("Значение");
Значения = Таблица.ВыгрузитьКолонку("Значение");
Возврат СтрСоединить(Значения, ",");
КонецФункции
Функция РасшифровкаЯчейки(Статус, ЕстьОшибки, ПроблемаВДанных) Экспорт
Массив = Новый Массив;
Массив.Добавить(Статус);
Массив.Добавить(ЕстьОшибки);
Массив.Добавить(ПроблемаВДанных);
Возврат Массив;
КонецФункции
Процедура СброситьПрогрессВыполненияОбработчиков()
Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
Возврат;
КонецЕсли;
Набор = РегистрыСведений.ПрогрессОбновления.СоздатьНаборЗаписей();
Набор.Записать();
КонецПроцедуры
Процедура ДобавитьИнформациюОбОшибкеВОбработчике(ИмяОбработчика) Экспорт
Если Не ЗначениеЗаполнено(ИмяОбработчика) Тогда
ТекстОшибки = НСтр("ru = 'Не удалось сохранить информацию об ошибке в обработчике
|по причине:
|Возможно вызов выполняется не из обработчика обновления.'");
ЗаписатьОшибку(ТекстОшибки);
Возврат;
КонецЕсли;
БлокировкаДанных = Новый БлокировкаДанных;
ЭлементБлокировкиДанных = БлокировкаДанных.Добавить("РегистрСведений.ОбработчикиОбновления");
ЭлементБлокировкиДанных.УстановитьЗначение("ИмяОбработчика", ИмяОбработчика);
НачатьТранзакцию();
Попытка
БлокировкаДанных.Заблокировать();
МенеджерЗаписи = РегистрыСведений.ОбработчикиОбновления.СоздатьМенеджерЗаписи();
МенеджерЗаписи.ИмяОбработчика = ИмяОбработчика;
МенеджерЗаписи.Прочитать();
СтатистикаВыполнения = МенеджерЗаписи.СтатистикаВыполнения;
СтатистикаВыполнения = СтатистикаВыполнения.Получить();
СтатистикаВыполнения.Вставить("ЕстьОшибки", Истина);
МенеджерЗаписи.СтатистикаВыполнения = Новый ХранилищеЗначения(СтатистикаВыполнения);
МенеджерЗаписи.Записать();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ИнформацияОбОшибке = ИнформацияОбОшибке();
ТекстОшибки = НСтр("ru = 'Не удалось сохранить информацию об ошибке в обработчике %1
|по причине:
|%2'");
ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстОшибки,
ИмяОбработчика, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));
ЗаписатьОшибку(ТекстОшибки);
КонецПопытки
КонецПроцедуры
Процедура Пауза(Секунд) Экспорт
ТекущийСеансИнформационнойБазы = ПолучитьТекущийСеансИнформационнойБазы();
ФоновоеЗадание = ТекущийСеансИнформационнойБазы.ПолучитьФоновоеЗадание();
Если ФоновоеЗадание = Неопределено Тогда
Параметры = Новый Массив;
Параметры.Добавить(Секунд);
ФоновоеЗадание = ФоновыеЗадания.Выполнить("ОбновлениеИнформационнойБазыСлужебный.Пауза", Параметры);
КонецЕсли;
ФоновоеЗадание.ОжидатьЗавершенияВыполнения(Секунд);
КонецПроцедуры
#КонецОбласти