RDT1C/src/DataProcessors/ирАнализТехножурнала/Ext/ObjectModule.bsl
Администратор 586adbc006 .
2022-12-11 19:51:11 +03:00

2746 lines
199 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

//ирПортативный Перем ирПортативный Экспорт;
//ирПортативный Перем ирОбщий Экспорт;
//ирПортативный Перем ирСервер Экспорт;
//ирПортативный Перем ирКэш Экспорт;
//ирПортативный Перем ирПривилегированный Экспорт;
Перем мТаблицаКолонок Экспорт;
Перем мСписокКолонок Экспорт;
//Перем КлючиЗагруженныхСтрок;
Перем мСвойстваСИменамиБД Экспорт;
Перем RegExpПараметры;
Перем RegExpМета;
Перем шБуква;
Перем шГраничныйСимволИмени;
//Перем МинимальнаяДатаЗагрузки Экспорт;
//Перем мЧисловыеСвойства;
Перем мИменаВозвращаемыхСвойств Экспорт;
Перем мТипСУБД Экспорт;
Перем мПлатформа Экспорт;
Перем мКартыФайлов Экспорт;
Перем мНепустыеКолонкиЖурнала Экспорт;
Перем мСерверныеТипыПроцессов Экспорт;
//Перем мСоставСвойствСобытий Экспорт;
Перем мСвойстваСобытий Экспорт;
Перем мАдресЧужойСхемыБД Экспорт;
Перем КонецПериодаКлиента Экспорт;
Перем НачалоПериодаКлиента Экспорт;
Перем КонецПериодаСервера Экспорт;
Перем НачалоПериодаСервера Экспорт;
Перем мИдентификаторТрассы Экспорт;
Перем мЛиТрассаПоПользователю Экспорт;
Перем мТрассаСУБДXML;
Перем мСоответствиеКолонок;
Перем мСоединениеАДО;
Перем мИдентификаторБазыДанных;
Перем мУдержательСоединенияБД;
Перем мИдентификаторСоединенияБД;
Перем мЛиСерверMSSQLПоддерживаетТрассировку;
Перем мТаблицаЖурнала;
// СдвигВремени - Число - в секундах задается, нужно для компенсации разницы времени между компьютерами
// ОтборПоПроцессу частично игнорируются когда ЗагружатьТолькоТекущийСеанс = Истина
Функция ПрочитатьПроизвольныйЖурнал(СообщитьРазмер = Неопределено, СдвигВремени = 0, ОтборПоПроцессу = Неопределено, ОтборПоСеансу = Неопределено,
НаСервере = Неопределено)
#Если Сервер И Не Сервер Тогда
мПлатформа = Обработки.ирПлатформа.Создать();
#КонецЕсли
НеизвестныеСвойства = Новый Соответствие();
Если Ложь
Или (НаСервере <> Неопределено И Не мЛиТрассаПоПользователю)
Или Не ЗначениеЗаполнено(КаталогЖурнала)
Тогда
КаталогЖурнала = ПолучитьКаталогТекущегоЖурнала(НаСервере = Истина);
Если Не ЗначениеЗаполнено(КаталогЖурнала) Тогда
Возврат Ложь;
КонецЕсли;
КонецЕсли;
Если Не ирОбщий.ЛиКаталогДоступенЛкс(КаталогЖурнала) Тогда
Возврат Ложь;
КонецЕсли;
Если НаСервере <> Истина Тогда
ОтборПоСеансу = Неопределено;
КонецЕсли;
Если мЛиТрассаПоПользователю Тогда
ОтборПоПользователю = ИмяПользователя();
КонецЕсли;
Если ЗагружатьТолькоТекущийСеанс Тогда
Если Ложь
Или ирКэш.ЛиФайловаяБазаЛкс()
Или НаСервере <> Истина
Тогда
ОтборПоПроцессу = мПлатформа.ИдентификаторПроцессаОС();
КонецЕсли;
Если ОтборПоСеансу = Неопределено Тогда
ОтборПоПользователю = ИмяПользователя();
КонецЕсли;
КонецЕсли;
лПоследнееВремяНачалаЗагрузки = ТекущаяДата();
Если ПериодПоследниеМинуты > 0 Тогда
НачалоПериода = лПоследнееВремяНачалаЗагрузки - 60 * ПериодПоследниеМинуты;
КонецПериода = Неопределено;
КонецЕсли;
//Если ТаблицаЖурнала.Количество() = 0 Тогда
// МинимальнаяДатаЗагрузки = ТекущаяДата() + 100000;
//КонецЕсли;
//Если МинимальнаяДатаЗагрузки > НачалоПериода Тогда
// ТаблицаЖурнала.Очистить();
//КонецЕсли;
//РежимДозагрузки = Истина
// И ТаблицаЖурнала.Количество() > 0
// И МинимальнаяДатаЗагрузки <= НачалоПериода;
Если СообщитьРазмер = Неопределено Тогда
СообщитьРазмер = (мКартыФайлов.Количество() = 0) Или КомментироватьЗагрузку;
КонецЕсли;
ирОбщий.ЛиКаталогТехножурналаНедоступенЛкс(КаталогЖурнала);
ФайлыЖурнала = НайтиФайлы(КаталогЖурнала, "*.log", Истина);
ОбщийРазмер = 0;
Для Каждого ФайлЖурнала Из ФайлыЖурнала Цикл
ОбщийРазмер = ОбщийРазмер + ФайлЖурнала.Размер();
КонецЦикла;
Если СообщитьРазмер Тогда
ирОбщий.СообщитьЛкс("В каталоге """ + КаталогЖурнала + """ обнаружено для обработки " + Формат(Цел(ОбщийРазмер / 1024), "ЧН=") + "КБ логов");
ПредставлениеОтбора = "";
Если СписокЗагружаемыхТиповСобытий.Количество() > 0 Тогда
ПредставлениеОтбора = ПредставлениеОтбора + " события " + СписокЗагружаемыхТиповСобытий;
КонецЕсли;
ПредставлениеПериода = ирОбщий.ПредставлениеПериодаЛкс(НачалоПериода, КонецПериода);
Если ЗначениеЗаполнено(ПредставлениеПериода) Тогда
ПредставлениеОтбора = ПредставлениеОтбора + " " + ПредставлениеПериода;
КонецЕсли;
Если ЗначениеЗаполнено("" + ФильтрЗагрузки) Тогда
Если ЗначениеЗаполнено(ПредставлениеОтбора) Тогда
ПредставлениеОтбора = ПредставлениеОтбора + " И";
КонецЕсли;
ПредставлениеОтбора = ПредставлениеОтбора + " " + ФильтрЗагрузки;
КонецЕсли;
Если ЗначениеЗаполнено(ОтборПоПроцессу) Тогда
Если ЗначениеЗаполнено(ПредставлениеОтбора) Тогда
ПредставлениеОтбора = ПредставлениеОтбора + " И";
КонецЕсли;
ПредставлениеОтбора = ПредставлениеОтбора + " Процесс=" + XMLСтрока(ОтборПоПроцессу);
КонецЕсли;
Если ЗначениеЗаполнено(ОтборПоСеансу) Тогда
Если ЗначениеЗаполнено(ПредставлениеОтбора) Тогда
ПредставлениеОтбора = ПредставлениеОтбора + " И";
КонецЕсли;
ПредставлениеОтбора = ПредставлениеОтбора + " Сеанс=" + XMLСтрока(ОтборПоСеансу);
КонецЕсли;
Если ЗначениеЗаполнено(ОтборПоПользователю) Тогда
Если ЗначениеЗаполнено(ПредставлениеОтбора) Тогда
ПредставлениеОтбора = ПредставлениеОтбора + " И";
КонецЕсли;
ПредставлениеОтбора = ПредставлениеОтбора + " Пользователь=""" + ОтборПоПользователю + """";
КонецЕсли;
Если ЗначениеЗаполнено(ПредставлениеОтбора) Тогда
ирОбщий.СообщитьЛкс("Отбор загрузки:" + ПредставлениеОтбора);
КонецЕсли;
// Проверяем только на клиенте для снижения вероятности ошибки "Не найден файл внешней компоненты" https://www.hostedredmine.com/issues/937706
#Если Клиент Тогда
Если мПлатформа.ИдентификаторыПроцессовОтладчиков().Количество() > 0 Тогда
ирОбщий.СообщитьЛкс("Возможно подключен отладчик и тогда он замедляет загрузку логов. Отключите отладчик для ускорения загрузки.");
КонецЕсли;
#КонецЕсли
КонецЕсли;
//лНачалоПериода = НачалоПериода;
//Если Не РежимДозагрузки Тогда
// //ТаблицаЖурнала.Очистить();
// КлючиЗагруженныхСтрок = Новый Соответствие;
//Иначе
// Если НаСервере = Истина Тогда
// лДатаЗагрузки = ПоследнееВремяНачалаЗагрузкиСервера;
// Иначе
// лДатаЗагрузки = ПоследнееВремяНачалаЗагрузки;
// КонецЕсли;
// Если ЗначениеЗаполнено(лДатаЗагрузки) Тогда
// лНачалоПериода = лДатаЗагрузки - НаложениеПриДозагрузкеСекунд;
// КонецЕсли;
//КонецЕсли;
Если УдалятьДанныеВнеПериода Тогда
ТаблицаЖурнала.Сортировать("МоментВремени");
КоличествоСтрок = ТаблицаЖурнала.Количество();
Пока Истина
И КоличествоСтрок > 0
И ТаблицаЖурнала[0].Дата < НачалоПериода
Цикл
ТаблицаЖурнала.Удалить(0);
КоличествоСтрок = КоличествоСтрок - 1;
КонецЦикла;
Если ЗначениеЗаполнено(КонецПериода) Тогда
ИндексСтроки = КоличествоСтрок - 1;
Пока Истина
И КоличествоСтрок > 0
И ТаблицаЖурнала[ИндексСтроки].Дата > КонецПериода
Цикл
ТаблицаЖурнала.Удалить(ИндексСтроки);
ИндексСтроки = ИндексСтроки - 1;
КонецЦикла;
КонецЕсли;
КонецЕсли;
#Если Сервер И Не Сервер Тогда
ЗагрузитьРезультатЧтенияФайлаВПотоке();
ПрочитатьФайлЖурнала();
#КонецЕсли
СтруктураПотоков = ирОбщий.НоваяСтруктураМногопоточнойОбработкиЛкс("ПрочитатьФайлЖурнала", ЭтотОбъект, "ЗагрузитьРезультатЧтенияФайлаВПотоке", 1, КоличествоПотоков);
Если СтруктураПотоков.ФактическоеКоличествоПотоков > 1 Тогда
ЗаголовокИндикации = "Выполняем загрузку в " + СтруктураПотоков.ФактическоеКоличествоПотоков + " потоков";
КонецЕсли;
Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ОбщийРазмер, "Загрузка журнала");
РазмерОбработанныхДанных = 0;
Для Каждого ФайлЖурнала Из ФайлыЖурнала Цикл
#Если Сервер И Не Сервер Тогда
ФайлЖурнала = Новый Файл;
#КонецЕсли
Попытка
РазмерФайла = ФайлЖурнала.Размер();
Исключение
ирОбщий.СообщитьЛкс("Пропускаем недоступный файл " + ФайлЖурнала.ПолноеИмя, СтатусСообщения.Внимание);
Продолжить;
КонецПопытки;
РазмерОбработанныхДанных = РазмерОбработанныхДанных + РазмерФайла;
Если ирОбщий.ОбработатьИндикаторЛкс(Индикатор, РазмерОбработанныхДанных) Тогда
Если ирОбщий.ЛиПрерватьФоновоеЗаданиеЛкс(Индикатор) Тогда
Прервать;
КонецЕсли;
КонецЕсли;
ПолноеИмяКаталогаПроцесса = Лев(ФайлЖурнала.Путь, СтрДлина(ФайлЖурнала.Путь) - 1);
Длина1 = СтрДлина(ПолноеИмяКаталогаПроцесса);
СтрокаЧасаЗаписи = "20" + Сред(ФайлЖурнала.ПолноеИмя, Длина1 + 2, 8);
ДатаЧасЗаписи = Дата(СтрокаЧасаЗаписи + "0000");
ИдентификаторПроцессаСтрока = ирОбщий.СтрокаБезКонцаЛкс(ирОбщий.ПоследнийФрагментЛкс(ФайлЖурнала.Путь, "_"), 1);
Попытка
ИдентификаторПроцесса = Число(ИдентификаторПроцессаСтрока);
Исключение
Если КомментироватьЗагрузку Тогда
ирОбщий.СообщитьЛкс("Пропускаем файл " + ФайлЖурнала.ПолноеИмя + " из каталога с некорректным именем", СтатусСообщения.Внимание);
КонецЕсли;
Продолжить;
КонецПопытки;
//ЛиДатаВИнтервале = ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(ДатаЧасЗаписи, НачалоЧаса(лНачалоПериода), НачалоЧаса(КонецПериода));
ЛиДатаВИнтервале = ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(ДатаЧасЗаписи, НачалоЧаса(НачалоПериода), НачалоЧаса(КонецПериода));
Если Ложь
Или Не ЛиДатаВИнтервале
Или (Истина
И ОтборПоПроцессу <> Неопределено
И ИдентификаторПроцесса <> ОтборПоПроцессу)
Тогда
Продолжить;
КонецЕсли;
Попытка
ЧтениеТекста = Новый ЧтениеТекста(ФайлЖурнала.ПолноеИмя, КодировкаТекста.UTF8, ,,Ложь);
//ТекстовыйДокумент.Прочитать(ФайлЖурнала.ПолноеИмя, КодировкаТекста.UTF8);
Исключение
ирОбщий.СообщитьЛкс("Не удалось прочитать открыть для чтения файл " + ФайлЖурнала.ПолноеИмя, СтатусСообщения.Внимание);
Продолжить;
КонецПопытки;
СигнатураФайла = ЧтениеТекста.Прочитать(20); // Для идентификации файла
Если ПустаяСтрока(СигнатураФайла) Тогда
Продолжить;
КонецЕсли;
ЧтениеТекста.Закрыть();
ПараметрыОбработкиФайла = Новый Структура;
ПараметрыОбработкиФайла.Вставить("ОтборПоПроцессу", ОтборПоПроцессу);
ПараметрыОбработкиФайла.Вставить("ОтборПоСеансу", ОтборПоСеансу);
ПараметрыОбработкиФайла.Вставить("ОтборПоПользователю", ОтборПоПользователю);
ПараметрыОбработкиФайла.Вставить("СдвигВремени", СдвигВремени);
ПараметрыОбработкиФайла.Вставить("ФильтрЗагрузки", ФильтрЗагрузки);
ПараметрыОбработкиФайла.Вставить("НомерСеанса", НомерСеансаИнформационнойБазы());
ПараметрыОбработкиФайла.Вставить("мКартыФайлов", мКартыФайлов);
ПараметрыОбработкиФайла.Вставить("КоличествоЗагруженныхСобытий", мТаблицаЖурнала.Количество());
ПараметрыОбработкиФайла.Вставить("ФайлЖурнала", ФайлЖурнала.ПолноеИмя);
ЛокальныеПараметры = Новый Структура;
ЛокальныеПараметры.Вставить("Индикатор", Индикатор);
ЛокальныеПараметры.Вставить("РазмерОбработанныхДанных", РазмерОбработанныхДанных);
ирОбщий.ДобавитьОбъектВОчередьМногопоточнойОбработкиЛкс(СтруктураПотоков, ПараметрыОбработкиФайла, ЛокальныеПараметры, РазмерФайла < 100000);
Если ТаблицаЖурнала.Количество() > МаксТысячСобытий * 1000 Тогда
Прервать;
КонецЕсли;
КонецЦикла;
ирОбщий.ОжидатьЗавершенияВсехПотоковОбработкиЛкс(СтруктураПотоков);
ирОбщий.ОсвободитьИндикаторПроцессаЛкс();
УдалитьСтрокиВнеФильтра();
//КлючиЗагруженныхСтрок = НовыеКлючиЗагруженныхСтрок;
//Если НаСервере = Истина Тогда
// ЭтотОбъект.ПоследнееВремяНачалаЗагрузкиСервера = лПоследнееВремяНачалаЗагрузки;
//Иначе
// ЭтотОбъект.ПоследнееВремяНачалаЗагрузки = лПоследнееВремяНачалаЗагрузки;
//КонецЕсли;
//МинимальнаяДатаЗагрузки = Мин(НачалоПериода, МинимальнаяДатаЗагрузки);
ТаблицаЖурнала.Сортировать("МоментВремени");
//ТаблицаЖурнала.Сортировать("МоментВремениНачала");
ОпределитьНепустыеКолонки();
Возврат Истина;
КонецФункции
// Параметры:
// ОтборПоПроцессу - ? -
// ОтборПоСеансу - Число -
// РазмерФайла - Примитивный -
// СдвигВремени - ? -
// ФайлЖурнала - Файл -
// ФильтрЗагрузки - ? -
// ТипВыхода - Строка - Служебный параметр для перехода после вызова метода
Функция ПрочитатьФайлЖурнала(Параметры) Экспорт
мКартыФайлов = Параметры.мКартыФайлов;
ОтборПоПроцессу = Параметры.ОтборПоПроцессу;
ОтборПоСеансу = Параметры.ОтборПоСеансу;
ОтборПоПользователю = Параметры.ОтборПоПользователю;
СдвигВремени = Параметры.СдвигВремени;
ФайлЖурнала = Параметры.ФайлЖурнала;
ФильтрЗагрузки = Параметры.ФильтрЗагрузки;
КоличествоЗагруженныхСобытий = Параметры.КоличествоЗагруженныхСобытий;
ВозвращатьРезультат = Параметры.НомерСеанса <> НомерСеансаИнформационнойБазы();
ДостигнутоПредельноеКоличество = Ложь;
ДобавитьОбязательныеНепустыеКолонки();
ФайлЖурнала = Новый Файл(ФайлЖурнала);
РазмерФайла = ФайлЖурнала.Размер();
РегВыражение1 = мПлатформа.RegExp;
РегВыражение2 = мПлатформа.RegExp2;
#Если Сервер И Не Сервер Тогда
РегВыражение1 = Обработки.ирОболочкаРегВыражение.Создать();
РегВыражение2 = РегВыражение1;
мПлатформа = Обработки.ирПлатформа.Создать();
мТаблицаЖурнала = ТаблицаЖурнала;
#КонецЕсли
шСимвол = "[" + шБуква + "\d\._#{}-]";
//ШаблонСвойствоЗначение = "([\w\:]+)=(?:'\s*((?:.|\n|\r)*?)'|""\s*([^""]*)""|([^'""\n\r,]*))(?:,|\r|$)"; // Так были очень большие трассы вычисления RegExp
ШаблонСвойствоЗначение = "([\w\:]+)=(?:'\s*([\s\S]*?)'|""\s*((?:""""|[^""])*)""|([^'""\n\r,]*))(?:,|\r|\n|$)+";
Шаблон = "(\d\d:\d\d)\.(\d+)-(\d+),(" + шСимвол + "+),(\d+),((?:" + ШаблонСвойствоЗначение + ")*)";
РегВыражение1.Pattern = Шаблон;
//RegExp.Multiline = Истина;
РегВыражение1.Global = Истина;
РегВыражение2.Pattern = ШаблонСвойствоЗначение;
РегВыражение2.Global = Истина;
ПустаяДата = Дата("00010101");
МаксКоличествоСобытий = КоличествоЗагруженныхСобытий + МаксТысячСобытий * 1000;
//НовыеКлючиЗагруженныхСтрок = Новый Соответствие();
Если КомментироватьЗагрузку Тогда
ирОбщий.СообщитьЛкс("Читаем " + ФайлЖурнала.ПолноеИмя + ", размер - " + РазмерФайла);
КонецЕсли;
ПолноеИмяКаталогаПроцесса = Лев(ФайлЖурнала.Путь, СтрДлина(ФайлЖурнала.Путь) - 1);
Длина1 = СтрДлина(ПолноеИмяКаталогаПроцесса);
СтрокаЧасаЗаписи = "20" + Сред(ФайлЖурнала.ПолноеИмя, Длина1 + 2, 8);
ДатаЧасЗаписи = Дата(СтрокаЧасаЗаписи + "0000");
ИдентификаторПроцессаСтрока = ирОбщий.СтрокаБезКонцаЛкс(ирОбщий.ПоследнийФрагментЛкс(ФайлЖурнала.Путь, "_"), 1);
ИдентификаторПроцесса = Число(ИдентификаторПроцессаСтрока);
//ЛиФайлВИнтервалеПолностью = ирОбщий.ЛиДатаВИнтервалеБезГраницЛкс(ДатаЧасЗаписи, НачалоЧаса(лНачалоПериода), НачалоЧаса(КонецПериода));
//ЛиДатаВИнтервале = ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(ДатаЧасЗаписи, НачалоЧаса(лНачалоПериода), НачалоЧаса(КонецПериода));
ЛиФайлВИнтервалеПолностью = ирОбщий.ЛиДатаВИнтервалеБезГраницЛкс(ДатаЧасЗаписи, НачалоЧаса(НачалоПериода), НачалоЧаса(КонецПериода));
ЛиДатаВИнтервале = ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(ДатаЧасЗаписи, НачалоЧаса(НачалоПериода), НачалоЧаса(КонецПериода));
ТекстФайла = ""; // Уничтожаем старый текст, т.к. он может быть очень большим
Попытка
ЧтениеТекста = Новый ЧтениеТекста(ФайлЖурнала.ПолноеИмя, КодировкаТекста.UTF8, ,,Ложь);
//ТекстовыйДокумент.Прочитать(ФайлЖурнала.ПолноеИмя, КодировкаТекста.UTF8);
Исключение
ирОбщий.СообщитьЛкс("Не удалось прочитать данные из файла " + ФайлЖурнала.ПолноеИмя, СтатусСообщения.Внимание);
Возврат Неопределено;
КонецПопытки;
СигнатураФайла = ЧтениеТекста.Прочитать(20); // Для идентификации файла
Если ПустаяСтрока(СигнатураФайла) Тогда
Возврат Неопределено;
КонецЕсли;
РазмерПорции = 2 * 1000 * 1000; // Подобрано экспериментально
КраткоеИмяКаталогаПроцесса = ирОбщий.ПоследнийФрагментЛкс(ПолноеИмяКаталогаПроцесса, "\");
ЧислоПорций = Цел(РазмерФайла / РазмерПорции) + 1;
ЧтениеТекста = Новый ЧтениеТекста(ФайлЖурнала.ПолноеИмя, КодировкаТекста.UTF8, ,,Ложь);
АбсолютнаяПозицияВФайле = 0;
КлючКарты = Новый Структура("ИмяКаталогаПроцесса, ИмяТекущегоФайла, СигнатураТекущегоФайла, ОтборПоСеансу",
КраткоеИмяКаталогаПроцесса, ФайлЖурнала.Имя, СигнатураФайла, "" + ЗагружатьТолькоТекущийСеанс + ОтборПоСеансу);
СтрокиКарт = мКартыФайлов.НайтиСтроки(КлючКарты);
Если СтрокиКарт.Количество() > 0 Тогда
КартаФайла = СтрокиКарт[0];
Иначе
КартаФайла = мКартыФайлов.Добавить();
ЗаполнитьЗначенияСвойств(КартаФайла, КлючКарты);
КартаФайла.КонецПериода = Дата(1000, 1, 1);
КонецЕсли;
Если ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(НачалоПериода, КартаФайла.НачалоПериода, КартаФайла.КонецПериода) Тогда
АбсолютнаяПозицияВФайле = КартаФайла.ПозицияКонца;
ИначеЕсли Ложь
Или НачалоПериода > КартаФайла.НачалоПериода
Или КонецПериода < КартаФайла.КонецПериода
Тогда
// Периоды не сшиваются. Очищаем карту.
КартаФайла.ПозицияНачала = -1;
КартаФайла.ПозицияКонца = -1;
КартаФайла.НачалоПериода = НачалоПериода;
КартаФайла.КонецПериода = КонецПериода;
КартаФайла.ДатаИзмененияФайла = Неопределено;
КонецЕсли;
Если АбсолютнаяПозицияВФайле > 0 Тогда
Если ЗначениеЗаполнено(КартаФайла.ДатаИзмененияФайла) Тогда
Если КартаФайла.ДатаИзмененияФайла = ФайлЖурнала.ПолучитьВремяИзменения() + ирКэш.ПолучитьСмещениеВремениЛкс() Тогда
Возврат Неопределено;
КонецЕсли;
КонецЕсли;
ЧтениеТекста.Прочитать(АбсолютнаяПозицияВФайле);
КонецЕсли;
ПозицияНачалаСчитанныхДанных = -1;
Если ЧислоПорций > 1 Тогда
ИндикаторФайла = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ЧислоПорций, "" + КраткоеИмяКаталогаПроцесса + "\" + ФайлЖурнала.Имя);
Иначе
ИндикаторФайла = Неопределено;
КонецЕсли;
РазрешенныеТипыСобытий = Неопределено;
Если СписокЗагружаемыхТиповСобытий.Количество() > 0 Тогда
РазрешенныеТипыСобытий = Новый Структура;
Для Каждого ТипСобытия Из СписокЗагружаемыхТиповСобытий.ВыгрузитьЗначения() Цикл
РазрешенныеТипыСобытий.Вставить(ТипСобытия);
КонецЦикла;
КонецЕсли;
СтрокаТЧ = Неопределено;
РазмерТекущейПорции = 0;
ПоследниеСобытияПоТипам = Новый Соответствие;
Пока Истина Цикл
КартаФайла.ДатаИзмененияФайла = ФайлЖурнала.ПолучитьВремяИзменения() + ирКэш.ПолучитьСмещениеВремениЛкс();
ПорцияТекстаФайла = ЧтениеТекста.Прочитать(РазмерПорции);
Если Ложь
Или ПорцияТекстаФайла = Неопределено
Или ПустаяСтрока(ПорцияТекстаФайла)
Тогда
Прервать;
КонецЕсли;
Если ИндикаторФайла <> Неопределено Тогда
Если ирОбщий.ОбработатьИндикаторЛкс(ИндикаторФайла) Тогда
Если ирОбщий.ЛиПрерватьФоновоеЗаданиеЛкс(ИндикаторФайла) Тогда
Прервать;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если Истина
И АбсолютнаяПозицияВФайле >= КартаФайла.ПозицияНачала
И АбсолютнаяПозицияВФайле + СтрДлина(ПорцияТекстаФайла) + СтрДлина(ТекстФайла) < КартаФайла.ПозицияКонца
Тогда
АбсолютнаяПозицияВФайле = АбсолютнаяПозицияВФайле + СтрДлина(ПорцияТекстаФайла) + СтрДлина(ТекстФайла);
Продолжить;
КонецЕсли;
ТекстФайла = ТекстФайла + ПорцияТекстаФайла;
РазборТекстаРазрешен = Истина;
ОписаниеОшибки = "";
МаксимальныйРазмерТекстДляАнализа = 20000000; // Экспериментально подобрано http://devtool1c.ucoz.ru/forum/2-270-1#1145
Если СтрДлина(ТекстФайла) > МаксимальныйРазмерТекстДляАнализа Тогда
Если Истина
И РазмерТекущейПорции = РазмерПорции
И СтрокаТЧ <> Неопределено
Тогда
СтрокаТЧ.ТекстSDBL = "<?>";
СтрокаТЧ.ТекстСУБД = "<?>";
ирОбщий.СообщитьЛкс("При анализе файла """ + ФайлЖурнала.ПолноеИмя + """ некоторые свойства события пропущены, т.к. оно превышает допустимый размер "
+ XMLСтрока(Цел(МаксимальныйРазмерТекстДляАнализа/1024/1024)) + "МБ: " + Лев(СокрЛ(СтрЗаменить(ТекстФайла, Символы.ПС, "")), 80) + "...");
Иначе
ОписаниеОшибки = "Событие превышает допустимый размер 20МБ";
КонецЕсли;
РазборТекстаРазрешен = Ложь;
Иначе
Если Истина
И РазмерТекущейПорции = РазмерПорции
И СтрокаТЧ <> Неопределено
Тогда
мТаблицаЖурнала.Удалить(СтрокаТЧ);
КонецЕсли;
КонецЕсли;
Вхождения = РегВыражение1.НайтиВхождения("");
Если РазборТекстаРазрешен Тогда
Попытка
Вхождения = РегВыражение1.НайтиВхождения(ТекстФайла);
Исключение
ОписаниеОшибки = ОписаниеОшибки();
КонецПопытки;
КонецЕсли;
Если ОписаниеОшибки <> "" Тогда
ирОбщий.СообщитьЛкс("При анализе файла """ + ФайлЖурнала.ПолноеИмя + """ пропущена порция """ + Лев(СокрЛ(СтрЗаменить(ТекстФайла, Символы.ПС, "")), 80) + "..."":
| " + ОписаниеОшибки);
Иначе
Если КомментироватьЗагрузку Тогда
ирОбщий.СообщитьЛкс("Анализ порции " + СтрДлина(ТекстФайла) + " символов обнаружил " + Вхождения.Количество() + " событий");
КонецЕсли;
КонецЕсли;
СтрокаТекущегоКонтекста = Неопределено;
СтрокаТЧ = Неопределено;
Вхождение = Неопределено;
Для Каждого Вхождение Из Вхождения Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
СтрокаТЧ = Неопределено;
АбсолютнаяПозицияВхождения = АбсолютнаяПозицияВФайле + Вхождение.FirstIndex;
Если Истина
И КартаФайла.ПозицияНачала > -1
И АбсолютнаяПозицияВхождения >= КартаФайла.ПозицияНачала
И АбсолютнаяПозицияВхождения < КартаФайла.ПозицияКонца
Тогда
Продолжить;
КонецЕсли;
СтрокаВремениЗаписи = СтрокаЧасаЗаписи + СтрЗаменить(Вхождение.SubMatches(0), ":", "");
ДатаТекущегоСобытия = Дата(СтрокаВремениЗаписи);
Если Не ЛиФайлВИнтервалеПолностью Тогда
//ЛиДатаВИнтервале = ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(ДатаТекущегоСобытия, лНачалоПериода, КонецПериода);
//Если Не ЛиДатаВИнтервале Тогда
// Продолжить;
//КонецЕсли;
Если Истина
И ЗначениеЗаполнено(НачалоПериода)
И ДатаТекущегоСобытия < НачалоПериода
Тогда
Продолжить;
КонецЕсли;
Если Истина
И ЗначениеЗаполнено(КонецПериода)
И ДатаТекущегоСобытия > КонецПериода
Тогда
Вхождение = Неопределено;
Прервать;
КонецЕсли;
КонецЕсли;
ТипСобытия = ВРег(Вхождение.SubMatches(3));
Если Истина
И РазрешенныеТипыСобытий <> Неопределено
И Не РазрешенныеТипыСобытий.Свойство(ТипСобытия)
Тогда
Продолжить;
КонецЕсли;
Если ПозицияНачалаСчитанныхДанных = -1 Тогда
ПозицияНачалаСчитанныхДанных = АбсолютнаяПозицияВхождения;
КонецЕсли;
КонецМикросекунды = Вхождение.SubMatches(1);
//КлючСтроки = МоментВремени + ";" + ФайлЖурнала.ПолноеИмя;
//Если РежимДозагрузки Тогда
// Если КлючиЗагруженныхСтрок[КлючСтроки] = 1 Тогда
// Продолжить;
// КонецЕсли;
//КонецЕсли;
Если СтрДлина(КонецМикросекунды) = 6 Тогда
//Это 8.3
ЧислоМикросекунд = Число(КонецМикросекунды);
ПродолжительностьВМикросекундах = Число(Вхождение.SubMatches(2));
Иначе
//Это 8.2
ЧислоМикросекунд = Число(КонецМикросекунды) * 100;
ПродолжительностьВМикросекундах = Число(Вхождение.SubMatches(2)) * 100;
КонецЕсли;
Если мТаблицаЖурнала.Количество() = МаксКоличествоСобытий Тогда
УдалитьСтрокиВнеФильтра();
Если мТаблицаЖурнала.Количество() = МаксКоличествоСобытий Тогда
ДостигнутоПредельноеКоличество = Истина;
Прервать;
КонецЕсли;
КонецЕсли;
СтрокаТЧ = мТаблицаЖурнала.Добавить();
ТекстДинамическихСвойств = Вхождение.SubMatches(5);
ПоследнееСобытиеТипа = ПоследниеСобытияПоТипам[ТипСобытия];
ДинамическиеСвойстваВзятыИзКэша = Истина
И ПоследнееСобытиеТипа <> Неопределено
И ПоследнееСобытиеТипа.ТекстДинамическихСвойств = ТекстДинамическихСвойств
И мТаблицаЖурнала.Индекс(ПоследнееСобытиеТипа.СтрокаТаблицы) >= 0; // Строку, на которую ссылается кэш, могли удалить на стыке порций. Поэтому проверяем ее существование
Если ДинамическиеСвойстваВзятыИзКэша Тогда
Если ТипЗнч(ПоследнееСобытиеТипа.СписокСвойств) = Тип("Массив") Тогда
ПоследнееСобытиеТипа.СписокСвойств = ирОбщий.СтрСоединитьЛкс(ПоследнееСобытиеТипа.СписокСвойств);
КонецЕсли;
ЗаполнитьЗначенияСвойств(СтрокаТЧ, ПоследнееСобытиеТипа.СтрокаТаблицы, ПоследнееСобытиеТипа.СписокСвойств);
Иначе
ДинамическиеСвойстваВзятыИзКэша = Ложь;
КонецЕсли;
СтрокаТЧ.ИмяФайлаЛога = ФайлЖурнала.ПолноеИмя;
СтрокаТЧ.ПроцессОС = ИдентификаторПроцесса;
СтрокаТЧ.Событие = ТипСобытия;
СтрокаТЧ.Дата = ДатаТекущегоСобытия - СдвигВремени;
СтрокаТЧ.МоментВремени = ПолучитьМоментВремени(СтрокаТЧ.Дата, КонецМикросекунды);
//СтрокаТЧ.ТекстЖурнала = Вхождение.Value; // Теперь это только для отладки будем включать
СтрокаТЧ.Длительность = ПродолжительностьВМикросекундах / 1000; // Переводим длительность в миллисекунды
Длительность1Секунды = Цел(ПродолжительностьВМикросекундах / 1000000);
Длительность1Микросекунды = ПродолжительностьВМикросекундах - Длительность1Секунды * 1000000;
ДатаНачала = СтрокаТЧ.Дата - Длительность1Секунды;
НачалоМикросекунды = КонецМикросекунды - Длительность1Микросекунды;
Если НачалоМикросекунды < 0 Тогда
ДатаНачала = ДатаНачала - 1;
НачалоМикросекунды = 1000000 + НачалоМикросекунды;
КонецЕсли;
СтрокаТЧ.ДатаНачала = ДатаНачала;
СтрокаТЧ.МоментВремениНачала = ПолучитьМоментВремени(ДатаНачала, НачалоМикросекунды);
СтрокаТЧ.Вложенность = Число(Вхождение.SubMatches(4));
Если Не ДинамическиеСвойстваВзятыИзКэша Тогда
СписокСвойств = Новый Массив;
ВхожденияСвойств = РегВыражение2.НайтиВхождения(ТекстДинамическихСвойств,, Истина);
Если ирКэш.РежимОтладкиЛкс() Тогда
// Пассивный оригинал расположенного ниже однострочного кода. Выполняйте изменения синхронно в обоих вариантах.
Для Каждого ВхождениеСвойства Из ВхожденияСвойств Цикл
//Для Индекс = 0 По мТаблицаКолонок.Количество() - 1 Цикл
ИмяСвойства = ВхождениеСвойства.SubMatches(0);
ЗначениеСвойства = ВхождениеСвойства.SubMatches(3);
Если ЗначениеСвойства = Неопределено Тогда // Скорость критична
ЗначениеСвойства = ВхождениеСвойства.SubMatches(2);
КонецЕсли;
Если ЗначениеСвойства = Неопределено Тогда // Скорость критична
ЗначениеСвойства = ВхождениеСвойства.SubMatches(1);
КонецЕсли;
Если ЗначениеСвойства = Неопределено Тогда // Скорость критична
Продолжить;
КонецЕсли;
ИмяКолонкиТЧ = мСоответствиеКолонок[НРег(ИмяСвойства)];
Если ИмяКолонкиТЧ = Неопределено Тогда
СтрокаТЧ.НеизвестныеСвойства = СтрокаТЧ.НеизвестныеСвойства + ИмяСвойства + "=" + ЗначениеСвойства + ", ";
СписокСвойств.Добавить("НеизвестныеСвойства");
Иначе
//Если мЧисловыеСвойства.Свойство(ИмяКолонкиТЧ) Тогда
// Если Не ЗначениеЗаполнено(ЗначениеСвойства) Тогда
// ЗначениеСвойства = 0;
// Иначе
// Попытка
// ЗначениеСвойства = Число(ЗначениеСвойства);
// Исключение
// ВызватьИсключение "Некорректное представление """ + ЗначениеСвойства + """ значения числового свойства """ + ИмяКолонкиТЧ + """";
// КонецПопытки;
// КонецЕсли;
//КонецЕсли;
Если ТипЗнч(СтрокаТЧ[ИмяКолонкиТЧ]) = Тип("Булево") Тогда
ЗначениеСвойства = ?(ЗначениеСвойства = "1" Или Нрег(ЗначениеСвойства) = "true", Истина, Ложь);
КонецЕсли;
Если Не мНепустыеКолонкиЖурнала.Свойство(ИмяКолонкиТЧ) Тогда
Если ЗначениеЗаполнено(ЗначениеСвойства) Тогда
мНепустыеКолонкиЖурнала.Вставить(ИмяКолонкиТЧ);
КонецЕсли;
КонецЕсли;
Попытка
СтрокаТЧ[ИмяКолонкиТЧ] = ЗначениеСвойства;
Исключение
ВызватьИсключение "Некорректное представление """ + ЗначениеСвойства + """ значения свойства """ + ИмяКолонкиТЧ + """";
КонецПопытки;
СписокСвойств.Добавить(ИмяКолонкиТЧ);
КонецЕсли;
КонецЦикла;
Иначе
// Однострочный код использован для ускорения. Выше расположен оригинал. Выполняйте изменения синхронно в обоих вариантах. Преобразовано консолью кода из подсистемы "Инструменты разработчика" (http://devtool1c.ucoz.ru)
Для Каждого ВхождениеСвойства Из ВхожденияСвойств Цикл     ИмяСвойства = ВхождениеСвойства.SubMatches(0);   ЗначениеСвойства = ВхождениеСвойства.SubMatches(3);   Если ЗначениеСвойства = Неопределено Тогда   ЗначениеСвойства = ВхождениеСвойства.SubMatches(2);   КонецЕсли;   Если ЗначениеСвойства = Неопределено Тогда   ЗначениеСвойства = ВхождениеСвойства.SubMatches(1);   КонецЕсли;   Если ЗначениеСвойства = Неопределено Тогда   Продолжить;   КонецЕсли;   ИмяКолонкиТЧ = мСоответствиеКолонок[НРег(ИмяСвойства)];   Если ИмяКолонкиТЧ = Неопределено Тогда   СтрокаТЧ.НеизвестныеСвойства = СтрокаТЧ.НеизвестныеСвойства + ИмяСвойства + "=" + ЗначениеСвойства + ", ";   СписокСвойств.Добавить("НеизвестныеСвойства");   Иначе                         Если ТипЗнч(СтрокаТЧ[ИмяКолонкиТЧ]) = Тип("Булево") Тогда   ЗначениеСвойства = ?(ЗначениеСвойства = "1" Или Нрег(ЗначениеСвойства) = "true", Истина, Ложь);   КонецЕсли;   Если Не мНепустыеКолонкиЖурнала.Свойство(ИмяКолонкиТЧ) Тогда   Если ЗначениеЗаполнено(ЗначениеСвойства) Тогда   мНепустыеКолонкиЖурнала.Вставить(ИмяКолонкиТЧ);   КонецЕсли;   КонецЕсли;   Попытка   СтрокаТЧ[ИмяКолонкиТЧ] = ЗначениеСвойства;   Исключение   ВызватьИсключение "Некорректное представление """ + ЗначениеСвойства + """ значения свойства """ + ИмяКолонкиТЧ + """";   КонецПопытки;   СписокСвойств.Добавить(ИмяКолонкиТЧ);   КонецЕсли;   КонецЦикла;  
КонецЕсли;
//АбсолютнаяПозицияВФайле = АбсолютнаяПозицияВФайле + Вхождение.Length;
Если Ложь
Или (Истина
И ОтборПоСеансу <> Неопределено
И СтрокаТЧ.Сеанс <> ОтборПоСеансу)
Или (Истина
И ОтборПоПользователю <> Неопределено
И СтрокаТЧ.Пользователь <> ОтборПоПользователю)
Тогда
мТаблицаЖурнала.Удалить(СтрокаТЧ);
СтрокаТЧ = Неопределено;
#Если Сервер И Не Сервер Тогда
СтрокаТЧ = мТаблицаЖурнала.Добавить();
#КонецЕсли
Продолжить;
КонецЕсли;
//Если НаСервере <> Неопределено Тогда
// СтрокаТЧ.НаСервере = НаСервере;
//Иначе
Если Ложь
Или ТипСобытия = "SCOM"
Тогда
СтрокаТЧ.НаСервере = Истина;
Иначе
ИмяТипаПроцесса = "_" + СтрЗаменить(СтрокаТЧ.ТипПроцессаОС, "#", "");
Попытка
СтрокаТЧ.НаСервере = мСерверныеТипыПроцессов.Свойство(ИмяТипаПроцесса);
Исключение
// Бывают типы процессов с UID, к сожалению тогда невозможно определить
КонецПопытки;
КонецЕсли;
//КонецЕсли;
Если СтрокаТЧ.Контекст <> "" Тогда
КонтекстТД = Новый ТекстовыйДокумент;
КонтекстТД.УстановитьТекст(СтрокаТЧ.Контекст);
СтрокаТЧ.СтрокаМодуля = СокрЛП(КонтекстТД.ПолучитьСтроку(КонтекстТД.КоличествоСтрок()));
Если БазовыйУровеньСтека > 0 Тогда
ЗаполнитьСтрокуБазовогоУровня(СтрокаТЧ);
КонецЕсли;
КонецЕсли;
ПоследниеСобытияПоТипам[ТипСобытия] = Новый Структура("СтрокаТаблицы, ТекстДинамическихСвойств, СписокСвойств", СтрокаТЧ, ТекстДинамическихСвойств, СписокСвойств);
КонецЕсли;
//Если ДатаТекущегоСобытия > лПоследнееВремяНачалаЗагрузки - НаложениеПриДозагрузкеСекунд Тогда
// НовыеКлючиЗагруженныхСтрок[КлючСтроки] = 1;
//КонецЕсли;
Если ирОбщий.СтрокиРавныЛкс(ТипСобытия, "Context") Тогда
// Встроим контекст в предыдущие события
Индекс = мТаблицаЖурнала.Количество() - 2;
Пока Индекс >= 0 Цикл
СтрокаБезКонтекста = мТаблицаЖурнала[Индекс];
Индекс = Индекс - 1;
Если Ложь
Или СтрокаБезКонтекста.Сеанс <> СтрокаТЧ.Сеанс
Или СтрокаБезКонтекста.Инфобаза <> СтрокаТЧ.Инфобаза
Тогда
Прервать;
КонецЕсли;
Если СтрокаБезКонтекста.СтрокаМодуля <> "" Тогда
Прервать;
КонецЕсли;
ЗаполнитьЗначенияСвойств(СтрокаБезКонтекста, СтрокаТЧ, "СтрокаМодуля, Контекст");
КонецЦикла;
КонецЕсли;
КонецЦикла;
Если ДостигнутоПредельноеКоличество Тогда
Прервать;
КонецЕсли;
// Для отката к началу последнего события
РазмерТекущейПорции = СтрДлина(ПорцияТекстаФайла);
АбсолютнаяПозицияВФайле = АбсолютнаяПозицияВФайле + СтрДлина(ТекстФайла);
Если РазмерТекущейПорции = РазмерПорции Тогда
//Если СтрокаТЧ <> Неопределено Тогда
// ТаблицаЖурнала.Удалить(ТаблицаЖурнала.Количество() - 1);
//КонецЕсли;
Если Вхождение <> Неопределено Тогда
ТекстФайла = Сред(ТекстФайла, Вхождение.FirstIndex);
Иначе
ТекстФайла = Прав(ТекстФайла, 1000); // Страховка
КонецЕсли;
АбсолютнаяПозицияВФайле = АбсолютнаяПозицияВФайле - СтрДлина(ТекстФайла);
Иначе
ТекстФайла = "";
КонецЕсли;
КонецЦикла;
Если ИндикаторФайла <> Неопределено Тогда
ирОбщий.ОсвободитьИндикаторПроцессаЛкс();
КонецЕсли;
Если ДостигнутоПредельноеКоличество Тогда
ТекстСообщения = "Загрузка остановлена по достижению максимального количества событий в таблице";
Если Не ЗначениеЗаполнено("" + ФильтрЗагрузки) Тогда
ТекстСообщения = ТекстСообщения + ". Если задать фильтр отображения таблицы, то будет предложено применить его при загрузке нового журнала.";
КонецЕсли;
ирОбщий.СообщитьЛкс(ТекстСообщения);
Иначе
КартаФайла.ПозицияКонца = АбсолютнаяПозицияВФайле;
Если Истина
И ПозицияНачалаСчитанныхДанных <> -1
И (Ложь
Или КартаФайла.ПозицияНачала = -1
Или КартаФайла.ПозицияНачала > ПозицияНачалаСчитанныхДанных)
Тогда
КартаФайла.ПозицияНачала = ПозицияНачалаСчитанныхДанных;
КонецЕсли;
Если Ложь
Или Не ЗначениеЗаполнено(КонецПериода)
Или КонецПериода > КартаФайла.КонецПериода
Тогда
КартаФайла.КонецПериода = КонецПериода;
КонецЕсли;
Если Ложь
Или Не ЗначениеЗаполнено(НачалоПериода)
Или НачалоПериода < КартаФайла.НачалоПериода
Тогда
КартаФайла.НачалоПериода = НачалоПериода;
КонецЕсли;
КонецЕсли;
Результат = Неопределено;
Если ВозвращатьРезультат Тогда
Результат = Новый Структура;
Результат.Вставить("КлючКарты", КлючКарты);
Результат.Вставить("КартаФайла", ирОбщий.СтруктураИзСтрокиТаблицыИлиДереваИлиВыборкиЛкс(КартаФайла));
Результат.Вставить("ТаблицаЖурнала", мТаблицаЖурнала);
Результат.Вставить("РазмерФайла", РазмерФайла);
Результат.Вставить("НепустыеКолонкиЖурнала", мНепустыеКолонкиЖурнала);
КонецЕсли;
Возврат Результат;
КонецФункции
Процедура ЗагрузитьРезультатЧтенияФайлаВПотоке(Знач Результат, Знач ЛокальныеПараметры) Экспорт
Если Результат = Неопределено Тогда
Возврат;
КонецЕсли;
мТаблицаЖурнала = ирОбщий.ОбъединитьТаблицыЗначенийЛкс(Результат.ТаблицаЖурнала, мТаблицаЖурнала, Результат.НепустыеКолонкиЖурнала, мНепустыеКолонкиЖурнала);
ирОбщий.СкопироватьУниверсальнуюКоллекциюЛкс(Результат.НепустыеКолонкиЖурнала, мНепустыеКолонкиЖурнала);
СтрокиКарт = мКартыФайлов.НайтиСтроки(Результат.КлючКарты);
Если СтрокиКарт.Количество() > 0 Тогда
КартаФайла = СтрокиКарт[0];
Иначе
КартаФайла = мКартыФайлов.Добавить();
КонецЕсли;
ЗаполнитьЗначенияСвойств(КартаФайла, Результат.КартаФайла);
КонецПроцедуры
Функция _СписокСвойствИзСтруктуры(Знач СтруктураСвойств)
#Если Сервер И Не Сервер Тогда
СтруктураСвойств = Новый Структура;
#КонецЕсли
МассивСвойств = Новый Массив;
Для Каждого КлючИЗначение Из СтруктураСвойств Цикл
МассивСвойств.Добавить(КлючИЗначение.Ключ);
КонецЦикла;
СписокСвойств1 = ирОбщий.СтрСоединитьЛкс(МассивСвойств);
Возврат СписокСвойств1;
КонецФункции
Функция РеквизитыДляСервера(Параметры) Экспорт
//Результат = ирОбщий.РеквизитыОбработкиЛкс(ЭтотОбъект);
//
ИменаПередаваемыхСвойств = мИменаВозвращаемыхСвойств + ",
|мАдресЧужойСхемыБД,
|НачалоПериодаКлиента,
|КонецПериодаКлиента,
|НачалоПериодаСервера,
|КонецПериодаСервера,
|мИдентификаторТрассы";
Результат = Новый Структура(ИменаПередаваемыхСвойств);
ЗаполнитьЗначенияСвойств(Результат, ЭтотОбъект, ИменаПередаваемыхСвойств);
Для Каждого МетаРеквизит Из Метаданные().Реквизиты Цикл
Результат.Вставить(МетаРеквизит.Имя, ЭтотОбъект[МетаРеквизит.Имя]);
КонецЦикла;
Возврат Результат;
КонецФункции
Процедура УдалитьСтрокиВнеФильтра()
Если ЗначениеЗаполнено("" + ФильтрЗагрузки) Тогда
Построитель = Новый ПостроительЗапроса;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТаблицаЖурнала);
ирОбщий.СкопироватьОтборПостроителяЛкс(Построитель.Отбор, ФильтрЗагрузки);
ТаблицаЖурнала.Загрузить(Построитель.Результат.Выгрузить());
КонецЕсли;
КонецПроцедуры
Процедура ОпределитьНепустыеКолонки() Экспорт
Если мНепустыеКолонкиЖурнала.Количество() = 0 Тогда // Загрузили данные из файла
// Долгая операция
Для Каждого Реквизит Из Метаданные().ТабличныеЧасти.ТаблицаЖурнала.Реквизиты Цикл
Если ТаблицаЖурнала.НайтиСтроки(Новый Структура(Реквизит.Имя, Реквизит.Тип.ПривестиЗначение())).Количество() < ТаблицаЖурнала.Количество() Тогда
мНепустыеКолонкиЖурнала.Вставить(Реквизит.Имя);
КонецЕсли;
КонецЦикла;
КонецЕсли;
ДобавитьОбязательныеНепустыеКолонки();
//Пустота производных колонок
Если мНепустыеКолонкиЖурнала.Свойство("Контекст") Тогда
мНепустыеКолонкиЖурнала.Вставить("СтрокаМодуля");
мНепустыеКолонкиЖурнала.Вставить("СтрокаБазовогоМодуля");
КонецЕсли;
КонецПроцедуры
Процедура ДобавитьОбязательныеНепустыеКолонки() Экспорт
мНепустыеКолонкиЖурнала.Вставить("Событие");
мНепустыеКолонкиЖурнала.Вставить("ИмяФайлаЛога");
мНепустыеКолонкиЖурнала.Вставить("ПроцессОС");
мНепустыеКолонкиЖурнала.Вставить("НаСервере");
мНепустыеКолонкиЖурнала.Вставить("Вложенность");
мНепустыеКолонкиЖурнала.Вставить("Длительность");
мНепустыеКолонкиЖурнала.Вставить("Дата");
мНепустыеКолонкиЖурнала.Вставить("ДатаНачала");
мНепустыеКолонкиЖурнала.Вставить("МоментВремени");
мНепустыеКолонкиЖурнала.Вставить("МоментВремениНачала");
мНепустыеКолонкиЖурнала.Вставить("СтрокаМодуля");
мНепустыеКолонкиЖурнала.Вставить("НеизвестныеСвойства");
//мНепустыеКолонкиЖурнала.Вставить("Картинка");
КонецПроцедуры
Функция ПолучитьМоментВремени(Дата, Микросекунды) Экспорт
Результат = Формат(Дата, "ДФ=yyyyMMddHHmmss") + Формат(Микросекунды, "ЧЦ=6; ЧВН=; ЧГ=");
Возврат Результат;
КонецФункции
Функция РазностьМоментовВремени(МоментВремениУменьшаемый, МоментВремениВычитаемый) Экспорт
Если СтрДлина(МоментВремениВычитаемый) <> СтрДлина(МоментВремениВычитаемый) Тогда
ВызватьИсключение "Размерность моментов времени не совпадает";
КонецЕсли;
ДлинаЧастиДаты = 14;
ДатаУменьшаемая = Дата(Лев(МоментВремениУменьшаемый, ДлинаЧастиДаты));
ДатаВычитаемая = Дата(Лев(МоментВремениВычитаемый, ДлинаЧастиДаты));
РазрядностьДолейСекунд = СтрДлина(МоментВремениУменьшаемый) - ДлинаЧастиДаты;
РазностьСекунд = ДатаУменьшаемая - ДатаВычитаемая;
Результат = РазностьСекунд;
Для Счетчик = 1 По РазрядностьДолейСекунд Цикл
Результат = Результат * 10;
КонецЦикла;
Результат = Результат + Число(Сред(МоментВремениУменьшаемый, ДлинаЧастиДаты + 1)) - Число(Сред(МоментВремениВычитаемый, ДлинаЧастиДаты + 1));
Возврат Результат;
КонецФункции // РазностьМоментовВремени()
Функция ЗаполнитьСтрокуБазовогоУровня(СтрокаТЧ)
Если БазовыйУровеньСтека > 0 Тогда
//МаркерБазовогоМодуля = Символы.Таб + мИмяБазовогоМодуля + " : ";
//ПозицияМаркераМодуля = Найти(СтрокаТЧ.Контекст, МаркерБазовогоМодуля);
//КонецСтроки = Сред(СтрокаТЧ.Контекст, ПозицияМаркераМодуля + СтрДлина(МаркерБазовогоМодуля));
НовоеЗначение = СокрЛ(СтрПолучитьСтроку(СтрокаТЧ.Контекст, БазовыйУровеньСтека));
Иначе
НовоеЗначение = "";
КонецЕсли;
ирОбщий.ПрисвоитьЕслиНеРавноЛкс(СтрокаТЧ.СтрокаМодуляБазовогоУровня, НовоеЗначение);
Возврат Неопределено;
КонецФункции
// ПопытокЧтения - Число, используется только при РежимТрассы = Истина
Функция ПрочитатьСобственныйЖурналДвухСторон(УдалитьДополнительныеСобытия = Истина, ИменаНеполезныхКолонок = "", РежимТрассы = Истина, ЖдатьСекунд = 2, СмещениеБазовогоУровня = Неопределено,
ОтборПоСеансу = Неопределено)
Если РежимТрассы Тогда
Если мИдентификаторТрассы = Неопределено Тогда
Если Не ирКэш.ЛиФайловаяБазаЛкс() Тогда
ирОбщий.ЛиТехножурналВключенЛкс(Истина, Истина, Истина, мЛиТрассаПоПользователю);
КонецЕсли;
ирОбщий.ЛиТехножурналВключенЛкс(, Истина, Истина, мЛиТрассаПоПользователю);
Возврат Ложь;
КонецЕсли;
//ЭтотОбъект.ЗагружатьЖурналКлиента = Истина;
//ЭтотОбъект.ЗагружатьЖурналСервера = Не ирКэш.ЛиФайловаяБазаЛкс();
//ЭтотОбъект.ЗагружатьТолькоТекущийСеанс = Истина;
КонецЕсли;
ВыраниватьДатуПоСерверу = Ложь;
#Если Клиент Тогда
ВыраниватьДатуПоСерверу = ирОбщий.ВосстановитьЗначениеЛкс("ирАнализТехножурнала.ВыраниватьДатуПоСерверу") = Истина;
#КонецЕсли
Если РежимТрассы Тогда
РазницаВремениКлиентСервер = НачалоПериодаКлиента - НачалоПериодаСервера;
Иначе
РазницаВремениКлиентСервер = ирОбщий.РазницаВремениКлиентСерверЛкс();
КонецЕсли;
Если Истина
И Не ирКэш.Получить().ЭтоФайловаяБаза
И ЗагружатьЖурналСервера
Тогда
ЭтотОбъект.КаталогЖурнала = "";
Если ВыраниватьДатуПоСерверу Тогда
СдвигВремени = 0;
Иначе
СдвигВремени = -РазницаВремениКлиентСервер;
КонецЕсли;
РезультатСервера = ПрочитатьСобственныйЖурналОднойСтороны(НачалоПериодаСервера, КонецПериодаСервера, Истина, СдвигВремени, РежимТрассы, ЖдатьСекунд, СмещениеБазовогоУровня, ОтборПоСеансу);
Если РезультатСервера = Неопределено Тогда
ирОбщий.СообщитьЛкс("Не удалось найти маркеры трассы в логах техножурнала сервера " + КаталогЖурнала + ". Проверьте включенность регистрации события QERR в настройке техножурнала");
КонецЕсли;
КонецЕсли;
РезультатКлиента = Неопределено;
Если Ложь
Или Не РежимТрассы
Или Не мЛиТрассаПоПользователю
Или ирКэш.Получить().ЭтоФайловаяБаза
Тогда
#Если Клиент Тогда
Если ЗагружатьЖурналКлиента Тогда
ЭтотОбъект.КаталогЖурнала = "";
Если ВыраниватьДатуПоСерверу Тогда
СдвигВремени = РазницаВремениКлиентСервер;
Иначе
СдвигВремени = 0;
КонецЕсли;
РезультатКлиента = ПрочитатьСобственныйЖурналОднойСтороны(НачалоПериодаКлиента, КонецПериодаКлиента, Ложь, СдвигВремени, РежимТрассы, ЖдатьСекунд, СмещениеБазовогоУровня, ОтборПоСеансу);
Если РезультатКлиента = Неопределено Тогда
ирОбщий.СообщитьЛкс("Не удалось найти маркеры трассы в логах техножурнала клиента " + КаталогЖурнала + ". Проверьте включенность регистрации события QERR в настройке техножурнала");
КонецЕсли;
КонецЕсли;
#КонецЕсли
КонецЕсли;
Если УдалитьДополнительныеСобытия Тогда
УдалитьСтрокиПоОтборуЛкс(Новый Структура("Действие", "getExecSQLStatistics"));
УдалитьСтрокиПоОтборуЛкс(Новый Структура("Событие", "CONTEXT"));
КонецЕсли;
Если РежимТрассы Тогда
ЭтотОбъект.ВключитьСвойстваСИменамиМетаданных = Истина;
КонецЕсли;
Если Истина
И РезультатКлиента = Неопределено
И РезультатСервера = Неопределено
Тогда
Если мТаблицаЖурнала.Количество() = 0 Тогда
Возврат Ложь;
КонецЕсли;
КонецЕсли;
//Если ВключитьСвойстваСИменамиМетаданных Тогда
// ОбновитьСвойстваВТерминахМетаданных();
//КонецЕсли;
//ОбновитьСтрокиБазовогоУровня();
Возврат Истина;
КонецФункции
Функция ПрочитатьСобственныйЖурналОднойСтороны(НачалоПериода = Неопределено, КонецПериода = Неопределено, НаСервере = Истина, СдвигВремени = 0,
РежимТрассы = Истина, ЖдатьСекунд = 2, СмещениеБазовогоУровня = Неопределено, ОтборПоСеансу = Неопределено)
Если НачалоПериода <> Неопределено Тогда
ЭтотОбъект.НачалоПериода = НачалоПериода;
КонецЕсли;
Если КонецПериода <> Неопределено Тогда
ЭтотОбъект.КонецПериода = КонецПериода;
КонецЕсли;
ТехножурналВключен = ирОбщий.ЛиТехножурналВключенЛкс(НаСервере,, Истина, РежимТрассы И мЛиТрассаПоПользователю);
Если Истина
И Не ТехножурналВключен
И РежимТрассы
Тогда
Возврат Неопределено;
КонецЕсли;
МассивТиповСУБД = Новый Массив();
Если ирКэш.ЛиФайловаяБазаЛкс() Тогда
МассивТиповСУБД.Добавить("DBV8DBENG");
//ОтборТЧ = Новый Структура("Событие", "SDBL");
Иначе
МассивТиповСУБД.Добавить("DBMSSQL");
МассивТиповСУБД.Добавить("DBPOSTGRS");
МассивТиповСУБД.Добавить("DBORACLE");
МассивТиповСУБД.Добавить("DB2");
//ОтборТЧ = Новый Структура("Событие", "CONTEXT");
КонецЕсли;
СообщитьРазмер = Неопределено;
МаркерНачалаНайден = Ложь;
ДлительностьОднойПаузы = 0.5;
Для Счетчик = 1 По ЖдатьСекунд / ДлительностьОднойПаузы + 1 Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
Если Счетчик > 1 Тогда
ирОбщий.СостояниеЛкс("Ожидание техножурнала " + КаталогЖурнала + "...");
ирОбщий.ПаузаЛкс(ДлительностьОднойПаузы);
СообщитьРазмер = Ложь;
КонецЕсли;
ЖурналСчитан = ПрочитатьПроизвольныйЖурнал(СообщитьРазмер, СдвигВремени, , ОтборПоСеансу, НаСервере);
Если Не ЖурналСчитан Тогда
Возврат Неопределено;
КонецЕсли;
//ТехножурналВключен = ирОбщий.ЛиТехножурналВключенЛкс(Истина,, Истина);
//Если ТехножурналВключен Тогда
// Если АвтоочисткаТехножурнала Тогда
// КаталогТекущегоЖурнала = ПолучитьКаталогТекущегоЖурнала();
// Если ЗначениеЗаполнено(КаталогТекущегоЖурнала) Тогда
// ирОбщий.ОчиститьКаталогТехножурналаЛкс(КаталогТекущегоЖурнала, Истина, Ложь);
// КонецЕсли;
// КонецЕсли;
//КонецЕсли;
Если РежимТрассы Тогда
Если Ложь
Или Не ирКэш.ЛиПортативныйРежимЛкс()
Или Не НаСервере
Тогда
МаркерНачала = Новый Структура("Описание", "{(1, 1)}: Ожидается выражение ""ВЫБРАТЬ""
|<<?>>НачалоТрассы_" + мИдентификаторТрассы);
МаркерКонца = Новый Структура("Описание", "{(1, 1)}: Ожидается выражение ""ВЫБРАТЬ""
|<<?>>КонецТрассы_" + мИдентификаторТрассы);
Иначе
МаркерНачала = Новый Структура("ТекстSDBL", "SELECT
|""НачалоТрассы_" + мИдентификаторТрассы + """
|");
МаркерКонца = Новый Структура("ТекстSDBL", "SELECT
|""КонецТрассы_" + мИдентификаторТрассы + """
|");
КонецЕсли;
// Удаляем лишние строки до маркера начала и после маркера конца
Если Не МаркерНачалаНайден Тогда
НайденныеСтроки = мТаблицаЖурнала.НайтиСтроки(МаркерНачала);
Если НайденныеСтроки.Количество() = 0 Тогда
Продолжить;
КонецЕсли;
НачальнаяСтрока = НайденныеСтроки[0];
#Если Сервер И Не Сервер Тогда
НачальнаяСтрока = мТаблицаЖурнала.Добавить();
#КонецЕсли
Если СмещениеБазовогоУровня <> Неопределено Тогда
ЭтотОбъект.БазовыйУровеньСтека = СтрЧислоСтрок(НачальнаяСтрока.Контекст) + СмещениеБазовогоУровня;
КонецЕсли;
КонечныйИндекс = мТаблицаЖурнала.Индекс(НачальнаяСтрока);
Для Индекс = 0 По КонечныйИндекс Цикл
//Если мТаблицаЖурнала[0].НаСервере = НаСервере Тогда
мТаблицаЖурнала.Удалить(0);
//КонецЕсли;
КонецЦикла;
МаркерНачалаНайден = Истина;
КонецЕсли;
НайденныеСтроки = мТаблицаЖурнала.НайтиСтроки(МаркерКонца);
Если НайденныеСтроки.Количество() = 0 Тогда
Продолжить;
КонецЕсли;
КонечнаяСтрока = НайденныеСтроки[0];
НачальныйИндекс = мТаблицаЖурнала.Индекс(КонечнаяСтрока);
Если Ложь
Или НаСервере
Или ирКэш.ЛиФайловаяБазаЛкс()
Тогда
КонечнаяСтрока1 = мТаблицаЖурнала[НачальныйИндекс];
Если МассивТиповСУБД.Найти(КонечнаяСтрока1.Событие) <> Неопределено Тогда // Опасно. Учитывается регистр букв
мТипСУБД = КонечнаяСтрока1.Событие;
НачальныйИндекс = НачальныйИндекс - 1;
КонецЕсли;
КонецЕсли;
НачальноеКоличество = мТаблицаЖурнала.Количество();
Для Индекс = 1 По НачальноеКоличество - НачальныйИндекс Цикл
СтрокаЖурнала = мТаблицаЖурнала[НачальноеКоличество - Индекс];
Если СтрокаЖурнала.НаСервере = НаСервере Тогда
мТаблицаЖурнала.Удалить(СтрокаЖурнала);
КонецЕсли;
КонецЦикла;
Пока Истина
И мТаблицаЖурнала.Количество() > 0
И мТаблицаЖурнала[0].НаСервере = НаСервере
И Найти(мТаблицаЖурнала[0].Контекст, "Обработка.ирАнализТехножурнала.МодульОбъекта") > 0
Цикл
мТаблицаЖурнала.Удалить(0);
КонецЦикла;
Пока Истина
И мТаблицаЖурнала.Количество() > 0
И мТаблицаЖурнала[мТаблицаЖурнала.Количество() - 1].НаСервере = НаСервере
И Найти(мТаблицаЖурнала[мТаблицаЖурнала.Количество() - 1].Контекст, "Обработка.ирАнализТехножурнала.МодульОбъекта") > 0
Цикл
мТаблицаЖурнала.Удалить(мТаблицаЖурнала.Количество() - 1);
КонецЦикла;
КонецЕсли;
Прервать;
КонецЦикла;
Если РежимТрассы Тогда
Если КонечнаяСтрока = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
// ФрагментыНачальнойСтрокиМодуля = ирОбщий.СтрРазделитьЛкс(мТаблицаЖурнала[0].СтрокаМодуля, ":", Истина);
// ФрагментыКонечнойСтрокиМодуля = ирОбщий.СтрРазделитьЛкс(мТаблицаЖурнала[мТаблицаЖурнала.Количество() - 1].СтрокаМодуля, ":", Истина);
// ИмяМодуляНачальнойСтроки = ФрагментыНачальнойСтрокиМодуля[0];
// ИмяМодуляКонечнойСтроки = ФрагментыКонечнойСтрокиМодуля[0];
// НомерНачальнойСтроки = Число(ФрагментыНачальнойСтрокиМодуля[1]);
// НомерКонечнойСтроки = Число(ФрагментыКонечнойСтрокиМодуля[1]);
// ЕстьВызовыМетодовМодулей = Ложь
// Или ИмяМодуляНачальнойСтроки <> ИмяМодуляНачальнойСтроки
// Или НомерНачальнойСтроки > НомерКонечнойСтроки;
// СтрокиВызововМетодов = НайтиВызовыМетодовМодулей(ИмяМодуляНачальнойСтроки, НомерНачальнойСтроки, НомерКонечнойСтроки, Истина);
// Если СтрокиВызововМетодов.Количество() > 0 Тогда
// Ответ = Вопрос("В трассе обнаружены вызовы методов модулей. Хотите удалить их из трассы?", РежимДиалогаВопрос.ДаНет);
// Если Ответ = КодВозвратаДиалога.Да Тогда
// СтрокиВызововМетодов = НайтиВызовыМетодовМодулей(ИмяМодуляНачальнойСтроки, НомерНачальнойСтроки, НомерКонечнойСтроки, Ложь);
// Для Каждого СтрокаВызоваМетода Из СтрокиВызововМетодов Цикл
// мТаблицаЖурнала.Удалить(СтрокаВызоваМетода);
// КонецЦикла;
// КонецЕсли;
// КонецЕсли;
КонецЕсли;
Возврат Истина;
КонецФункции
Функция ПрочитатьЖурнал(Параметры) Экспорт
ЭтотОбъект.ФильтрЗагрузки = Параметры.ФильтрЗагрузки;
УдалитьДополнительныеСобытия = Параметры.УдалитьДополнительныеСобытия;
ИменаНеполезныхКолонок = Параметры.ИменаНеполезныхКолонок;
РежимТрассы = Параметры.РежимТрассы;
ЖдатьСекунд = Параметры.ЖдатьСекунд;
ОтборПоСеансу = Параметры.ОтборПоСеансу;
СмещениеБазовогоУровня = Параметры.СмещениеБазовогоУровня;
Если Не РежимТрассы Тогда
ЭтотОбъект.КонецПериодаСервера = Неопределено;
ЭтотОбъект.КонецПериодаКлиента = Неопределено;
ЭтотОбъект.НачалоПериодаСервера = Неопределено;
ЭтотОбъект.НачалоПериодаКлиента = Неопределено;
КонецЕсли;
Если Ложь
Или ЗагружатьЖурналКлиента
Или ЗагружатьЖурналСервера
Тогда
ЖурналПрочитан = ПрочитатьСобственныйЖурналДвухСторон(УдалитьДополнительныеСобытия, ИменаНеполезныхКолонок, РежимТрассы, ЖдатьСекунд, СмещениеБазовогоУровня, ОтборПоСеансу);
Иначе
ЖурналПрочитан = ПрочитатьПроизвольныйЖурнал(,,, ОтборПоСеансу);
Если ВключитьСвойстваСИменамиМетаданных Тогда
ОбновитьСвойстваВТерминахМетаданных();
КонецЕсли;
КонецЕсли;
Результат = Новый Структура(мИменаВозвращаемыхСвойств);
ЗаполнитьЗначенияСвойств(Результат, ЭтотОбъект);
Результат.Вставить("Успех", ЖурналПрочитан);
Результат.Вставить("ТаблицаЖурнала", мТаблицаЖурнала);
Возврат Результат;
КонецФункции
// ТолькоПустые - заполнять только ранее не заполненные свойства
Функция ЗаполнитьСвойстваСИменамиМетаданных(ВыбраннаяСтрока, Принудительно = Ложь) Экспорт
Если Не Принудительно И ВыбраннаяСтрока.СвойстваСИменамиМетаданныхАктуальны Тогда
Возврат Ложь;
КонецЕсли;
Попытка
Инфобаза = ВыбраннаяСтрока.Инфобаза;
Исключение
Инфобаза = "";
КонецПопытки;
ЧужаяСхемаБД = ирОбщий.ПолучитьЧужуюСхемуБДЛкс(мАдресЧужойСхемыБД);
ЭтоГарантированоСобытиеВыбраннойЧужойБазы = Истина
И ЗначениеЗаполнено(Инфобаза)
И ЧужаяСхемаБД <> Неопределено
И ирОбщий.СтрокиРавныЛкс(Инфобаза, НСтр(ЧужаяСхемаБД.СтрокаСоединения, "Ref"));
ЭтоГарантированоСобытиеСобственнойБазы = Истина
И ЗначениеЗаполнено(Инфобаза)
И Не ЭтоГарантированоСобытиеВыбраннойЧужойБазы
И ирОбщий.СтрокиРавныЛкс(Инфобаза, НСтр(СтрокаСоединенияИнформационнойБазы(), "Ref"));
НайденныеТаблицы = Новый ТаблицаЗначений;
Для Каждого КлючИЗначение Из мСвойстваСИменамиБД Цикл
ИмяСвойства = КлючИЗначение.Ключ;
Если Найти(ИмяСвойства, "Шаблон") > 0 Тогда
Продолжить;
КонецЕсли;
Попытка
Пустышка = ТипЗнч(ВыбраннаяСтрока[ИмяСвойства]); // т.к. строки длинные, то их копирование в новую переменную накладно
Исключение
// Такого свойства нет - пропускаем
Продолжить;
КонецПопытки;
ЗначениеСвойства = ВыбраннаяСтрока[ИмяСвойства];
// Берем только имя базы, т.к. кластер может быть по-разному написан
Если Истина
И ЗначениеЗаполнено(ЗначениеСвойства)
И (Ложь
Или Инфобаза = ""
Или ЭтоГарантированоСобытиеСобственнойБазы
Или ЭтоГарантированоСобытиеВыбраннойЧужойБазы)
Тогда
ЛиМенаБД = КлючИЗначение.Значение;
Если Не ЛиМенаБД Тогда
ТипСУБД = "";
Иначе
Попытка
ТипСУБД = ВыбраннаяСтрока.Событие;
Исключение
ТипСУБД = Сред(ИмяСвойства, СтрДлина("Текст") + 1); // Опасно
КонецПопытки;
КонецЕсли;
//Попытка
ТекстМета = ПеревестиТекстБДВТерминыМетаданных(ЗначениеСвойства, , , ТипСУБД, НайденныеТаблицы,, Ложь,, ЭтоГарантированоСобытиеСобственнойБазы);
//Исключение
// ТекстМета = "";
//КонецПопытки;
//Если ТекстМета <> "" Тогда
ВыбраннаяСтрока[ИмяСвойства + "Мета"] = ТекстМета;
//КонецЕсли;
Иначе
// База чужая. Не делаем преобразования
//ВыбраннаяСтрока[ИмяСвойства + "Мета"] = ЗначениеСвойства;
КонецЕсли;
КонецЦикла;
Если НайденныеТаблицы.Количество() > 0 Тогда
НайденныеТаблицы.Свернуть("ИмяМета");
НайденныеТаблицы.Сортировать("ИмяМета");
мНепустыеКолонкиЖурнала.Вставить("ТаблицыМетаданных");
ИменаТаблицСтрокой = ирОбщий.СтрСоединитьЛкс(НайденныеТаблицы.ВыгрузитьКолонку("ИмяМета"));
Попытка
ВыбраннаяСтрока.ТаблицыМетаданных = ИменаТаблицСтрокой;
Исключение
// Строка итогов БлокировкиУпр
КонецПопытки;
КонецЕсли;
Попытка
ТекстSDBLШаблонМета = ВыбраннаяСтрока.ТекстSDBLШаблонМета;
Исключение
ТекстSDBLШаблонМета = Неопределено;
КонецПопытки;
Если ТекстSDBLШаблонМета <> Неопределено Тогда
Инфобаза = "";
ТекстSDBLМета = "";
Попытка
Инфобаза = ВыбраннаяСтрока.Инфобаза;
ТекстSDBLМета = ВыбраннаяСтрока.ТекстSDBLМета;
Исключение
КонецПопытки;
Если Ложь
Или Инфобаза = ""
Или ЭтоГарантированоСобытиеСобственнойБазы
Или ЭтоГарантированоСобытиеВыбраннойЧужойБазы
Тогда
Если Истина
И ТекстSDBLМета <> ""
Тогда
ВыбраннаяСтрока.ТекстSDBLШаблонМета = ПолучитьШаблонТекстаБД(ТекстSDBLМета);
Иначе
ВыбраннаяСтрока.ТекстSDBLШаблонМета = ПеревестиТекстБДВТерминыМетаданных(ВыбраннаяСтрока.ТекстSDBLШаблон,,,,,, Ложь,, ЭтоГарантированоСобытиеСобственнойБазы);
КонецЕсли;
КонецЕсли;
КонецЕсли;
Попытка
ТекстСУБДШаблонМета = ВыбраннаяСтрока.ТекстСУБДШаблонМета;
Исключение
ТекстСУБДШаблонМета = Неопределено;
КонецПопытки;
Если ТекстСУБДШаблонМета <> Неопределено Тогда
Инфобаза = "";
ТекстСУБДМета = "";
Попытка
Инфобаза = ВыбраннаяСтрока.Инфобаза;
ТекстСУБДМета = ВыбраннаяСтрока.ТекстСУБДМета;
Исключение
КонецПопытки;
Если Ложь
Или Инфобаза = ""
Или ЭтоГарантированоСобытиеСобственнойБазы
Или ЭтоГарантированоСобытиеВыбраннойЧужойБазы
Тогда
Если Истина
И ТекстСУБДМета <> ""
Тогда
ВыбраннаяСтрока.ТекстСУБДШаблонМета = ПолучитьШаблонТекстаБД(ТекстСУБДМета);
Иначе
ВыбраннаяСтрока.ТекстСУБДШаблонМета = ПеревестиТекстБДВТерминыМетаданных(ВыбраннаяСтрока.ТекстСУБДШаблон,,, мТипСУБД,,, Ложь,, ЭтоГарантированоСобытиеСобственнойБазы);
КонецЕсли;
КонецЕсли;
КонецЕсли;
ВыбраннаяСтрока.СвойстваСИменамиМетаданныхАктуальны = Истина;
Возврат Истина;
КонецФункции
Функция ПолучитьКаталогТекущегоЖурнала(НаСервере) Экспорт
Результат = ирОбщий.КаталогЧтенияТехножурналаЛкс(НаСервере, Истина, мЛиТрассаПоПользователю);
Если Не ЗначениеЗаполнено(Результат) Тогда
Если НаСервере Тогда
ТекстКлиентСервер = "сервера";
Иначе
ТекстКлиентСервер = "клиента";
КонецЕсли;
ирОбщий.СообщитьЛкс("Технологический журнал " + ТекстКлиентСервер + " выключен. Невозможно определить каталог журнала по умолчанию.");
Возврат Неопределено;
КонецЕсли;
Если НаСервере Тогда
КлиентЗапущенНаКомпьютереСервера = ирОбщий.ЛиКлиентЗапущенНаКомпьютереСервераЛкс();
Если Не КлиентЗапущенНаКомпьютереСервера Тогда
Если ЭтоЛокальныйПутьЛкс(Результат) Тогда
ирОбщий.СообщитьЛкс("Клиент запущен не на компьютере сервера (" + ирСервер.ИмяКомпьютераЛкс() +
"), а в серверной настройке техножурнала указан локальный каталог. Необходимо указать сетевой путь к техножурналу сервера");
#Если Клиент Тогда
ФормаНастройки = ПолучитьФорму("НастройкаЧтения");
РезультатНастройки = ФормаНастройки.ОткрытьМодально();
Если РезультатНастройки = Истина Тогда
Если мЛиТрассаПоПользователю Тогда
Результат = ирОбщий.ВосстановитьЗначениеЛкс("ирАнализТехножурнала.КаталогТрассыПоПользователю");
Иначе
Результат = ирОбщий.ВосстановитьЗначениеЛкс("ирАнализТехножурнала.КаталогЖурналаСервера");
КонецЕсли;
Иначе
Результат = Неопределено;
КонецЕсли;
#КонецЕсли
КонецЕсли;
КонецЕсли;
КонецЕсли;
Возврат Результат;
КонецФункции
Функция ЭтоЛокальныйПутьЛкс(Путь) Экспорт
ЭтоЛокальныйРесурс = Ложь
Или Найти(НРег(Путь), "\\localhost") = 1
Или Найти(НРег(Путь), "\\127.0.0.1") = 1
Или Лев(Путь, 2) <> "\\";
Возврат ЭтоЛокальныйРесурс;
КонецФункции // ЭтоЛокальныйПуть()
Функция ОткрытьСПараметрами(пКаталогЖурнала) Экспорт
Форма = ПолучитьФорму();
Форма.Открыть();
ЭтотОбъект.ЗагружатьТолькоТекущийСеанс = Ложь;
ЭтотОбъект.ЗагружатьЖурналСервера = Ложь;
ЭтотОбъект.ЗагружатьЖурналКлиента = Ложь;
Форма.ОбновитьДоступность();
Форма.КаталогЖурнала = пКаталогЖурнала;
Возврат Форма;
КонецФункции
Функция ОткрытьСОтбором(НачалоПериода = Неопределено, КонецПериода = Неопределено, СтруктураОтбора = Неопределено) Экспорт
Форма = ПолучитьФорму(,,);
Форма.Открыть();
Отбор = Форма.ЭлементыФормы.ТаблицаЖурнала.ОтборСтрок;
Отбор.Сбросить();
Если НачалоПериода <> Неопределено Тогда
Форма.НачалоПериода = НачалоПериода;
КонецЕсли;
Если КонецПериода <> Неопределено Тогда
Форма.КонецПериода = КонецПериода;
КонецЕсли;
Если СтруктураОтбора <> Неопределено Тогда
Для Каждого КлючИЗначение Из СтруктураОтбора Цикл
Отбор[КлючИЗначение.Ключ].Установить(КлючИЗначение.Значение);
КонецЦикла;
КонецЕсли;
Возврат Форма;
КонецФункции
Функция ПолучитьИмяСвойстваБезМета(Знач МестноеИмя) Экспорт
Если ирОбщий.СтрокиРавныЛкс(Прав(МестноеИмя, 4), "мета") Тогда
МестноеИмя = Лев(МестноеИмя, СтрДлина(МестноеИмя) - 4);
КонецЕсли;
Возврат МестноеИмя;
КонецФункции
Процедура ОбновитьСвойстваВТерминахМетаданных() Экспорт
ВыбранныеСтроки = мТаблицаЖурнала.НайтиСтроки(Новый Структура("СвойстваСИменамиМетаданныхАктуальны", Ложь));
Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ВыбранныеСтроки.Количество(), "Перевод в термины метаданных");
Для Каждого СтрокаТаблицыЖурнала Из ВыбранныеСтроки Цикл
ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
ЗаполнитьСвойстваСИменамиМетаданных(СтрокаТаблицыЖурнала);
КонецЦикла;
ирОбщий.ОсвободитьИндикаторПроцессаЛкс();
КонецПроцедуры
Процедура ОбновитьСтрокиБазовогоУровня() Экспорт
//Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(мТаблицаЖурнала.Количество());
Для Каждого СтрокаТаблицыЖурнала Из мТаблицаЖурнала Цикл
//ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
ЗаполнитьСтрокуБазовогоУровня(СтрокаТаблицыЖурнала);
КонецЦикла;
//Для Каждого СтрокаКонтекста Из Контексты Цикл
// ЗаполнитьСтрокуБазовогоУровня(СтрокаКонтекста);
//КонецЦикла;
КонецПроцедуры
Функция ПолучитьШаблонТекстаБД(ТекстБД, Знач ЗаменаПеременныхФрагментов = "7") Экспорт
#Если Сервер И Не Сервер Тогда
RegExpПараметры = Обработки.ирОболочкаРегВыражение.Создать();
#КонецЕсли
СложнаяЗамена = RegExpПараметры.ТекущийДвижок() = "PCRE2";
Если СложнаяЗамена Тогда
// https://www.hostedredmine.com/issues/928414
Префикс = "[!@!~=+]";
ЗаменаПеременныхФрагментов = Префикс + ЗаменаПеременныхФрагментов;
КонецЕсли;
ШаблонТекстаБД = RegExpПараметры.Заменить(ТекстБД, "$1$2" + ЗаменаПеременныхФрагментов);
Если СложнаяЗамена Тогда
ШаблонТекстаБД = СтрЗаменить(ШаблонТекстаБД, Префикс, "");
КонецЕсли;
Возврат ШаблонТекстаБД;
КонецФункции
Процедура ЗаполнитьСвойстваШаблоны() Экспорт
Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ТаблицаЖурнала.Количество());
Для Каждого СтрокаТаблицыЖурнала Из ТаблицаЖурнала Цикл
ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
Если Истина
И СтрокаТаблицыЖурнала.ТекстSDBL <> ""
И СтрокаТаблицыЖурнала.ТекстSDBLШаблон = ""
Тогда
СтрокаТаблицыЖурнала.ТекстSDBLШаблон = ПолучитьШаблонТекстаБД(СтрокаТаблицыЖурнала.ТекстSDBL);
КонецЕсли;
Если Истина
И СтрокаТаблицыЖурнала.ТекстСУБД <> ""
И СтрокаТаблицыЖурнала.ТекстСУБДШаблон = ""
Тогда
СтрокаТаблицыЖурнала.ТекстСУБДШаблон = ПолучитьШаблонТекстаБД(СтрокаТаблицыЖурнала.ТекстСУБД);
КонецЕсли;
Если Истина
И СтрокаТаблицыЖурнала.Описание <> ""
И СтрокаТаблицыЖурнала.ОписаниеШаблон = ""
Тогда
СтрокаТаблицыЖурнала.ОписаниеШаблон = ПолучитьШаблонТекстаБД(СтрокаТаблицыЖурнала.Описание);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Процедура ОставитьТолькоСтрокиПоОтбору(СтруктураОтбора) Экспорт
НужныеСтроки = ТаблицаЖурнала.НайтиСтроки(СтруктураОтбора);
КоличествоСтрок = ТаблицаЖурнала.Количество();
Для Счетчик = 1 По КоличествоСтрок Цикл
Индекс = КоличествоСтрок - Счетчик;
СтрокаЖурнала = ТаблицаЖурнала[Индекс];
Если НужныеСтроки.Найти(СтрокаЖурнала) = Неопределено Тогда
ТаблицаЖурнала.Удалить(СтрокаЖурнала);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Процедура УдалитьСтрокиПоОтборуЛкс(СтруктураОтбора) Экспорт
НенужныеСтроки = мТаблицаЖурнала.НайтиСтроки(СтруктураОтбора);
Для Каждого НенужнаяСтрока Из НенужныеСтроки Цикл
мТаблицаЖурнала.Удалить(НенужнаяСтрока);
КонецЦикла;
КонецПроцедуры
Процедура ЗаписатьМаркерВТехножурнал(Маркер, ДляКлиента = Истина, ДляСервера = Истина, выхТекущаяДатаКлиента = Неопределено, выхТекущаяДатаСервера = Неопределено) Экспорт
ЗапросМаркер = Новый Запрос();
выхТекущаяДатаКлиента = ТекущаяДата();
выхТекущаяДатаСервера = выхТекущаяДатаКлиента;
Если ДляКлиента Тогда
ЗапросМаркер.Текст = Маркер;
Попытка
ЗапросМаркер.Выполнить(); // Генерируем для клиента маркер-событие QERR
Исключение
КонецПопытки;
КонецЕсли;
Если Истина
И ДляСервера
И Не ирКэш.ЛиФайловаяБазаЛкс()
Тогда
Если Не ирКэш.ЛиПортативныйРежимЛкс() Тогда
Попытка
ирСервер.ВыполнитьЗапросЛкс(Маркер,,,, выхТекущаяДатаСервера); // Генерируем для сервера маркер-событие QERR
Исключение
КонецПопытки;
Иначе
ЗапросМаркер.Текст = "ВЫБРАТЬ """ + Маркер + """";
Попытка
ЗапросМаркер.Выполнить(); // Генерируем для клиента маркер-событие SDBL
Исключение
// Может возникнуть ошибка "В данной транзакции уже происходили ошибки!"
КонецПопытки;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Функция ИдентификаторТрассыБД() Экспорт
ДатаМиллисекунды = ТекущаяУниверсальнаяДатаВМиллисекундах();
Генератор = Новый ГенераторСлучайныхЧисел(ДатаМиллисекунды);
СгенерированноеЧисло = Генератор.СлучайноеЧисло(100000000, 900000000);
Возврат СгенерированноеЧисло;
КонецФункции
Функция НачатьТрассу(ПрефиксТрассы = "", ВыводитьСообщения = Ложь, выхТекущаяДатаСервера = Неопределено) Экспорт
Если ВыводитьСообщения Тогда
// Попробовать сделать проверку регистрации событий QERR в настройке техножурнала на сервере
// Вызовы ЛиТехножурналВключенЛкс могут быть очень долгими, если в анализе техножурнала пользователь сохранил сетевой путь к логам на сервере и он недоступен
Если Не ирКэш.ЛиФайловаяБазаЛкс() Тогда
ТехножурналСервераВключен = ирОбщий.ЛиТехножурналВключенЛкс(Истина, ВыводитьСообщения,, мЛиТрассаПоПользователю);
КонецЕсли;
ТехножурналКлиентаВключен = ирОбщий.ЛиТехножурналВключенЛкс(, ВыводитьСообщения,, мЛиТрассаПоПользователю);
Если Истина
И ТехножурналСервераВключен <> Истина
И Не ТехножурналКлиентаВключен
Тогда
Возврат Ложь;
КонецЕсли;
КонецЕсли;
ЭтотОбъект.КонецПериодаСервера = Неопределено;
ЭтотОбъект.КонецПериодаКлиента = Неопределено;
ИспользоватьТрассуСУБД = Истина
И ирОбщий.ВосстановитьЗначениеЛкс("ирПараметрыСоединенияСУБД.СобиратьТрассу") = Истина
И ирОбщий.ЛиПровайдерАДОДляЭтойБазыГотовЛкс()
И ЛиСерверMSSQLПоддерживаетТрассировку();
мИдентификаторТрассы = ПрефиксТрассы + "_" + СтрЗаменить(Новый УникальныйИдентификатор(), "-", "");
ЗаписатьМаркерВТехножурнал("НачалоТрассы_" + мИдентификаторТрассы,,, НачалоПериодаКлиента, НачалоПериодаСервера);
выхТекущаяДатаСервера = НачалоПериодаСервера;
мУдержательСоединенияБД = Неопределено;
мИдентификаторСоединенияБД = Неопределено;
Если ИспользоватьТрассуСУБД Тогда
// https://www.hostedredmine.com/issues/926150
мИдентификаторБазыДанных = ИдентификаторБазыДанных();
ТекстЗапроса = ПолучитьМакет("SQLServer_СкриптОчисткиДанных").ПолучитьТекст();
ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ТекстЗапроса,,,,,, мСоединениеАДО);
ИдентификаторТрассы = XMLСтрока(ИдентификаторТрассыБД());
ИдентификаторСессии = XMLСтрока(НомерСеансаИнформационнойБазы());
ЗапросСозданияСессии = ПолучитьМакет("SQLServer_СкриптСессииОпределенияСессииСУБД").ПолучитьТекст();
ЗапросСозданияСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросСозданияСессии, "{ИдентификаторСессии}", ИдентификаторСессии);
ЗапросСозданияСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросСозданияСессии, "{ИдентификатоЗапроса}", XMLСтрока(ИдентификаторТрассы));
ЗапросСозданияСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросСозданияСессии, "{ИдентификаторБазыДанных}", мИдентификаторБазыДанных);
ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ЗапросСозданияСессии,,,,,, мСоединениеАДО);
мУдержательСоединенияБД = Новый МенеджерВременныхТаблиц;
ЗапросУдержаниеСоединения = Новый Запрос;
ЗапросУдержаниеСоединения.МенеджерВременныхТаблиц = мУдержательСоединенияБД;
ЗапросУдержаниеСоединения.Текст =
"ВЫБРАТЬ ПЕРВЫЕ " + ИдентификаторТрассы + "
| " + ИдентификаторТрассы + " КАК Число,
| 0293843834892983011884662710842 КАК ДополнительноеЧисло
|ПОМЕСТИТЬ ВТроизвольныеЗначения";
ЗапросУдержаниеСоединения.Выполнить();
ЗапросДанныеСессии = ПолучитьМакет("SQLServer_СкриптПолученияДанныхРасширенныхСобытий").ПолучитьТекст();
ЗапросДанныеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросДанныеСессии, "{ИмяСессии}", "getSessionForQuery");
ЗапросДанныеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросДанныеСессии, "{ИдентификаторСессии}", ИдентификаторСессии);
РезультатЗапроса = ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ЗапросДанныеСессии,,,,,, мСоединениеАДО);
Для Каждого СтрокаРезультата Из РезультатЗапроса Цикл
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СтрокаРезультата.Data);
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
Разыменователь = Новый РазыменовательПространствИменDOM(ДокументDOM);
НайденныеСобытия = ДокументDOM.ВычислитьВыражениеXPath("/RingBufferTarget/event", ДокументDOM, Разыменователь, ТипРезультатаDOMXPath.Любой);
УзелСобытие = НайденныеСобытия.ПолучитьСледующий();
Пока УзелСобытие <> Неопределено Цикл
СвойстваСобытия = Новый Соответствие;
Для Каждого ЭлементСобытия Из УзелСобытие.ДочерниеУзлы Цикл
ИмяСвойства = СокрЛП(ЭлементСобытия.Атрибуты.ПолучитьИменованныйЭлемент("name").Значение);
ЗначениеСвойства = СокрЛП(ЭлементСобытия.ПоследнийДочерний.ТекстовоеСодержимое);
Если Не ЗначениеЗаполнено(ЗначениеСвойства) Тогда
ЗначениеСвойства = СокрЛП(ЭлементСобытия.ТекстовоеСодержимое);
КонецЕсли;
СвойстваСобытия.Вставить(ИмяСвойства, ЗначениеСвойства);
КонецЦикла;
ТекстЗапроса = СвойстваСобытия["batch_text"];
Если Не ЗначениеЗаполнено(ТекстЗапроса) Тогда
ТекстЗапроса = СвойстваСобытия["statement"];
КонецЕсли;
Если Не ЗначениеЗаполнено(ТекстЗапроса) Тогда
ТекстЗапроса = СвойстваСобытия["sql_text"];
КонецЕсли;
Если Найти(ТекстЗапроса, "CREATE EVENT SESSION") > 0 Тогда
УзелСобытие = НайденныеСобытия.ПолучитьСледующий();
Продолжить;
ИначеЕсли Найти(ТекстЗапроса, ИдентификаторТрассы) > 0 Тогда
мИдентификаторСоединенияБД = СвойстваСобытия["session_id"];
Прервать;
КонецЕсли;
УзелСобытие = НайденныеСобытия.ПолучитьСледующий();
КонецЦикла;
КонецЦикла;
ЗапросУдалениеСессии = ПолучитьМакет("SQLServer_СкриптУдаленияСессииСбораДанных").ПолучитьТекст();
ЗапросУдалениеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросУдалениеСессии, "{ИмяСессии}", "getSessionForQuery");
ЗапросУдалениеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросУдалениеСессии, "{ИдентификаторСессии}", ИдентификаторСессии);
ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ЗапросУдалениеСессии,,,,,, мСоединениеАДО);
Если Не ЗначениеЗаполнено(мИдентификаторСоединенияБД) Тогда
мУдержательСоединенияБД = Неопределено;
ирОбщий.СообщитьЛкс("Не удалось определить идентификатор соединения СУБД. Трасса СУБД будет недоступна.");
КонецЕсли;
Если мИдентификаторСоединенияБД <> Неопределено Тогда
ЗапросСозданияСессии = ПолучитьМакет("SQLServer_СкриптСбораДанныхОЗапросах").ПолучитьТекст();
ЗапросСозданияСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросСозданияСессии, "{ИдентификаторСессии}", ИдентификаторСессии);
ЗапросСозданияСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросСозданияСессии, "{ИдентификаторСоединения}", XMLСтрока(мИдентификаторСоединенияБД));
ЗапросСозданияСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросСозданияСессии, "{ИдентификаторБазыДанных}", мИдентификаторБазыДанных);
ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ЗапросСозданияСессии,,,,,, мСоединениеАДО);
КонецЕсли;
КонецЕсли;
Возврат Истина;
КонецФункции
Функция ИдентификаторБазыДанных()
Если мИдентификаторБазыДанных <> Неопределено Тогда
Возврат мИдентификаторБазыДанных;
КонецЕсли;
РезультатЗапроса = ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс("SELECT DB_ID() AS DatabaseId",,,,,, мСоединениеАДО);
мИдентификаторБазыДанных = РезультатЗапроса[0][0];
Возврат мИдентификаторБазыДанных;
КонецФункции
Функция ЛиСерверMSSQLПоддерживаетТрассировку() Экспорт
Если мЛиСерверMSSQLПоддерживаетТрассировку <> Неопределено Тогда
Возврат мЛиСерверMSSQLПоддерживаетТрассировку;
КонецЕсли;
мЛиСерверMSSQLПоддерживаетТрассировку = Ложь;
РезультатЗапроса = ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс("SELECT @@VERSION AS SQLServerVersion",,,,,, мСоединениеАДО);
Если РезультатЗапроса <> Неопределено Тогда
ВерсияСУБД = РезультатЗапроса[0][0];
Если Найти(ВерсияСУБД, "Microsoft SQL Server 2008") = 0 Тогда
мЛиСерверMSSQLПоддерживаетТрассировку = Истина;
КонецЕсли;
КонецЕсли;
Возврат мЛиСерверMSSQLПоддерживаетТрассировку;
КонецФункции
Функция КончитьТрассу(выхТекущаяДатаСервера = Неопределено) Экспорт
Если ЗначениеЗаполнено(ЭтотОбъект.КонецПериодаКлиента) Тогда
Возврат Ложь;
КонецЕсли;
Если мИдентификаторСоединенияБД <> Неопределено Тогда
Попытка
ИдентификаторСессии = XMLСтрока(НомерСеансаИнформационнойБазы());
ЗапросДанныеСессии = ПолучитьМакет("SQLServer_СкриптПолученияДанныхРасширенныхСобытий").ПолучитьТекст();
ЗапросДанныеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросДанныеСессии, "{ИмяСессии}", "getQueriesInfo");
ЗапросДанныеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросДанныеСессии, "{ИдентификаторСессии}", ИдентификаторСессии);
РезультатБД = ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ЗапросДанныеСессии,,,,,, мСоединениеАДО);
Если РезультатБД.Количество() = 0 Тогда
ирОбщий.СообщитьЛкс("Трасса СУБД пуста. Вероятно была получена другим экземляром инструмента.");
Иначе
мТрассаСУБДXML = РезультатБД[0][0];
КонецЕсли;
Исключение
ирОбщий.СообщитьЛкс(ОписаниеОшибки());
КонецПопытки;
ТекстЗапроса = ПолучитьМакет("SQLServer_СкриптОчисткиДанных").ПолучитьТекст();
ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ТекстЗапроса,,,,,, мСоединениеАДО);
КонецЕсли;
ЗаписатьМаркерВТехножурнал("КонецТрассы_" + мИдентификаторТрассы,,, КонецПериодаКлиента, КонецПериодаСервера);
выхТекущаяДатаСервера = КонецПериодаСервера;
мУдержательСоединенияБД = Неопределено;
мИдентификаторСоединенияБД = Неопределено;
Возврат Истина;
КонецФункции
Процедура ЗагрузитьТрассуСУБД() Экспорт
Если Не ЗначениеЗаполнено(мТрассаСУБДXML) Тогда
Возврат;
КонецЕсли;
ИдентификаторСессии = XMLСтрока(НомерСеансаИнформационнойБазы());
НомерПоПорядку = 1;
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(мТрассаСУБДXML);
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
Разыменователь = Новый РазыменовательПространствИменDOM(ДокументDOM);
РезультатПоискаСобытий = ДокументDOM.ВычислитьВыражениеXPath("/RingBufferTarget/event", ДокументDOM, Разыменователь, ТипРезультатаDOMXPath.Любой);
МассивОператоров = Новый Массив;
МассивИДПланов = Новый Массив;
УзелСобытие = РезультатПоискаСобытий.ПолучитьСледующий();
НачальныйИндексСтроки = мТаблицаЖурнала.Количество();
Пока УзелСобытие <> Неопределено Цикл
ИмяСобытия = СокрЛП(УзелСобытие.Атрибуты.ПолучитьИменованныйЭлемент("name").ТекстовоеСодержимое);
СвойстваСобытия = Новый Соответствие;
Для Каждого ЭлементСобытия Из УзелСобытие.ДочерниеУзлы Цикл
ИмяСвойства = СокрЛП(ЭлементСобытия.Атрибуты.ПолучитьИменованныйЭлемент("name").Значение);
ЗначениеСвойства = СокрЛП(ЭлементСобытия.ПоследнийДочерний.ТекстовоеСодержимое);
Если НЕ ЗначениеЗаполнено(ЗначениеСвойства) Тогда
ЗначениеСвойства = СокрЛП(ЭлементСобытия.ТекстовоеСодержимое);
КонецЕсли;
СвойстваСобытия.Вставить(ИмяСвойства, ЗначениеСвойства);
КонецЦикла;
ТекстЗапроса = СвойстваСобытия["statement"];
Если НЕ ЗначениеЗаполнено(ТекстЗапроса) Тогда
ТекстЗапроса = СвойстваСобытия["batch_text"];
КонецЕсли;
Если НЕ ЗначениеЗаполнено(ТекстЗапроса) Тогда
ТекстЗапроса = СвойстваСобытия["sql_text"];
КонецЕсли;
Если Найти(ТекстЗапроса, "CREATE EVENT SESSION") > 0 Тогда
УзелСобытие = РезультатПоискаСобытий.ПолучитьСледующий();
Продолжить;
КонецЕсли;
Если ИмяСобытия = "rpc_completed" ИЛИ ИмяСобытия = "sql_batch_completed" Тогда
КонецМилисекунды = "";
ДатаСобытияСтрока = СокрЛП(УзелСобытие.Атрибуты.ПолучитьИменованныйЭлемент("timestamp").ТекстовоеСодержимое);
ДатаСобытияСтрока = ирОбщий.ПервыйФрагментЛкс(ДатаСобытияСтрока, "Z");
ДатаСобытия = МестноеВремя(ПреобразоватьКДате(ДатаСобытияСтрока, КонецМилисекунды));
ДлительностьМикросекунд = СвойстваСобытия["duration"];
ДатаНачала = ДатаСобытия - Цел(ДлительностьМикросекунд / 1000000);
МоментВремени = Формат(ДатаСобытия, "ДФ=ггггММддЧЧммсс") + КонецМилисекунды + Формат(НомерПоПорядку, "ЧЦ=3; ЧВН=");
НачалоМилисекунды = КонецМилисекунды - Цел(ДлительностьМикросекунд / 1000);
Если НачалоМилисекунды < 0 Тогда
ДатаНачала = ДатаНачала - 1;
НачалоМилисекунды = 1000 + НачалоМилисекунды;
КонецЕсли;
МоментВремениНачала = Формат(ДатаНачала, "ДФ=ггггММддЧЧммсс") + НачалоМилисекунды + Формат(НомерПоПорядку, "ЧЦ=3; ЧВН=");
СтрокаТаблицы = мТаблицаЖурнала.Добавить();
СтрокаТаблицы.МоментВремени = МоментВремени;
СтрокаТаблицы.Дата = ДатаСобытия;
СтрокаТаблицы.ДатаНачала = ДатаНачала;
СтрокаТаблицы.Длительность = ДлительностьМикросекунд / 1000;
СтрокаТаблицы.НаСервере = Истина;
СтрокаТаблицы.ТипПроцессаОС = "sqlservr";
СтрокаТаблицы.МоментВремениНачала = МоментВремениНачала;
СтрокаТаблицы.CPUTime = СвойстваСобытия["cpu_time"] / 1000;
СтрокаТаблицы.ЛогическиПрочитано = СвойстваСобытия["logical_reads"];
СтрокаТаблицы.ФизическиПрочитано = СвойстваСобытия["physical_reads"];
СтрокаТаблицы.ЛогическиЗаписано = СвойстваСобытия["writes"];
//СтрокаТаблицы.ИмяОбъекта = СвойстваСобытия["object_name"];
//СтрокаТаблицы.Приложение = СвойстваСобытия["client_app_name"];
//СтрокаТаблицы.ИдентификаторЯдраПроцессора = СвойстваСобытия["cpu_id"];
//СтрокаТаблицы.Соединение_ = СвойстваСобытия["client_pid"];
//СтрокаТаблицы.Системный = ПреобразоватьКБулево(СвойстваСобытия["is_system"]);
СтрокаТаблицы.ЧислоСтрок = СвойстваСобытия["row_count"];
СтрокаТаблицы.ТекстСУБД = ТекстЗапроса;
Если МассивОператоров.Количество() = 1 Тогда
ИдентификаторПланаЗапроса = МассивОператоров.Получить(0).Получить("plan_handle");
НачалоИдентификатораПланаЗапроса = "<plan handle='0x";
Если Найти(ИдентификаторПланаЗапроса, НачалоИдентификатораПланаЗапроса) > 0 Тогда
ДлинаИдентификатораПланаЗапроса = СтрДлина(ИдентификаторПланаЗапроса) - СтрДлина(НачалоИдентификатораПланаЗапроса) - 3;
ИдентификаторПланаЗапроса = Сред(ИдентификаторПланаЗапроса, СтрДлина(НачалоИдентификатораПланаЗапроса) + 1, ДлинаИдентификатораПланаЗапроса);
КонецЕсли;
СтрокаТаблицы.ПланСУБД = "0x" + ВРег(ИдентификаторПланаЗапроса);
МассивИДПланов.Добавить(СтрокаТаблицы.ПланСУБД);
КонецЕсли;
СтрокаТаблицы.Событие = ИмяСобытия;
СтрокаТаблицы.Дата = ДатаСобытия;
МассивОператоров.Очистить();
НомерПоПорядку = НомерПоПорядку + 1;
Иначе
МассивОператоров.Добавить(СвойстваСобытия);
КонецЕсли;
УзелСобытие = РезультатПоискаСобытий.ПолучитьСледующий();
КонецЦикла;
Если МассивИДПланов.Количество() > 0 Тогда
ТекстЗапроса = ПолучитьМакет("SQLServer_СкриптЧтенияПланаЗапроса").ПолучитьТекст();
ТекстЗапроса = ирОбщий.СтрЗаменитьЛкс(ТекстЗапроса, "{ИдентификаторПланаЗапроса}", ирОбщий.СтрСоединитьЛкс(МассивИДПланов));
ТаблицаПлановЗапросов = ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ТекстЗапроса,,,,,, мСоединениеАДО);
Для Индекс = НачальныйИндексСтроки По мТаблицаЖурнала.Количество() - 1 Цикл
СтрокаРезультата = ТаблицаПлановЗапросов.Найти(мТаблицаЖурнала[Индекс].ПланСУБД, "plan_handle");
Если СтрокаРезультата <> Неопределено Тогда
мТаблицаЖурнала[Индекс].ПланСУБД = СтрокаРезультата.query_plan;
Иначе
мТаблицаЖурнала[Индекс].ПланСУБД = МаркерПланЗапросаНеНайден();
КонецЕсли;
КонецЦикла;
КонецЕсли;
ЗапросУдалениеСессии = ПолучитьМакет("SQLServer_СкриптУдаленияСессииСбораДанных").ПолучитьТекст();
ЗапросУдалениеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросУдалениеСессии, "{ИмяСессии}", "getQueriesInfo");
ЗапросУдалениеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросУдалениеСессии, "{ИдентификаторСессии}", ИдентификаторСессии);
ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ЗапросУдалениеСессии);
мНепустыеКолонкиЖурнала.Очистить();
ОпределитьНепустыеКолонки();
КонецПроцедуры
Функция МаркерПланЗапросаНеНайден() Экспорт
Возврат "<Не найден в кэше СУБД>";
КонецФункции
Функция ПреобразоватьКБулево(Знач ИсходноеЗначение)
Если ТипЗнч(ИсходноеЗначение) = Тип("Строка") Тогда
ИсходноеЗначение = ВРег(ИсходноеЗначение);
Если ИсходноеЗначение = "TRUE" Тогда
Возврат Истина;
Иначе
Возврат Ложь;
КонецЕсли;
ИначеЕсли ТипЗнч(ИсходноеЗначение) = Тип("Булево") Тогда
Возврат ИсходноеЗначение;
ИначеЕсли ТипЗнч(ИсходноеЗначение) = Тип("Число") Тогда
Возврат (ИсходноеЗначение > 0);
Иначе
Возврат Ложь;
КонецЕсли;
КонецФункции
Функция ПреобразоватьКДате(Знач ИсходноеЗначение, выхТысячнаяДоляСекунды = "")
ДатаСтрока = СтрЗаменить(ИсходноеЗначение, "-", "");
ДатаСтрока = СтрЗаменить(ДатаСтрока, ":", "");
ДатаСтрока = СтрЗаменить(ДатаСтрока, "T", "");
Фрагменты = ирОбщий.СтрРазделитьЛкс(ДатаСтрока);
выхТысячнаяДоляСекунды = Фрагменты[1];
ДатаСтрока = Фрагменты[0];
ДатаЗначение = Неопределено;
Попытка
ДатаЗначение = Дата(ДатаСтрока);
Исключение
ДатаЗначение = Дата(1,1,1);
КонецПопытки;
Возврат ДатаЗначение;
КонецФункции
Функция ПолучитьТекстSQLДляПоискаВТехножурнале(Текст) Экспорт
RegExpМета.Pattern = "([^A-ZА-ЯЁ_0-9]|^)(?:@P\d+)";
Результат = RegExpМета.Заменить(Текст, "$1?");
Возврат Результат;
КонецФункции
#Если Клиент Тогда
Функция ПоказатьТрассу(УдалитьДополнительныеСобытия = Истина, ИменаНеполезныхКолонок = "", ЖдатьСекунд = 2, СмещениеБазовогоУровня = Неопределено, ЗагружатьТолькоТекущийСеанс = Ложь,
ЗагружатьЖурналКлиента = Истина, ЛиТрассаПоПользователю = Ложь) Экспорт
Если ЭтотОбъект.КонецПериодаСервера = Неопределено Тогда
Предупреждение("Сформируйте трассу заново");
Возврат Неопределено;
КонецЕсли;
ОчиститьТаблицуЖурнала();
лКаталогЖурнала = КаталогЖурнала;
мЛиТрассаПоПользователю = ЛиТрассаПоПользователю Или ЗагружатьТолькоТекущийСеанс;
ФормаАнализа = ПолучитьФорму();
ФормаАнализа.ЭтоТрасса = Истина;
ФормаАнализа.Открыть();
ФормаАнализа.ЗагружатьТолькоТекущийСеанс = ЗагружатьТолькоТекущийСеанс;
ФормаАнализа.ЗагружатьЖурналКлиента = ЗагружатьЖурналКлиента;
ФормаАнализа.ЗагружатьЖурналСервера = Не ирКэш.ЛиФайловаяБазаЛкс();
ВыраниватьДатуПоСерверу = ирОбщий.ВосстановитьЗначениеЛкс("ирАнализТехножурнала.ВыраниватьДатуПоСерверу") = Истина;
Если ВыраниватьДатуПоСерверу Тогда
ФормаАнализа.КонецПериода = КонецПериодаСервера;
ФормаАнализа.НачалоПериода = НачалоПериодаСервера;
Иначе
ФормаАнализа.КонецПериода = КонецПериодаКлиента;
ФормаАнализа.НачалоПериода = НачалоПериодаКлиента;
КонецЕсли;
ФормаАнализа.КаталогЖурнала = лКаталогЖурнала;
ФормаАнализа.ПериодПоследниеМинуты = 0;
ФормаАнализа.ОбновитьТаблицуЖурнала(УдалитьДополнительныеСобытия, ИменаНеполезныхКолонок, Истина, ЖдатьСекунд, СмещениеБазовогоУровня);
ФормаАнализа.УстановитьРежимИтогов(ТаблицаЖурнала.Количество() > 30);
ФормаАнализа.ОбновитьДоступность();
ФормаАнализа.ЭлементыФормы.ПанельНастройки.ТекущаяСтраница = ФормаАнализа.ЭлементыФормы.ПанельНастройки.Страницы.Анализ;
ФормаАнализа.УстановитьБесполезныеКолонки(ИменаНеполезныхКолонок);
мЛиТрассаПоПользователю = Ложь;
Возврат ФормаАнализа;
КонецФункции
Функция ОчиститьТаблицуЖурнала() Экспорт
мНепустыеКолонкиЖурнала = Новый Структура();
ТаблицаЖурнала.Очистить();
мКартыФайлов.Очистить();
Возврат Неопределено;
КонецФункции
Функция ОткрытьТекстБДВКонверторе(ТекстБД, СразуПеревестиВМета = Истина, КлючУникальности = Неопределено, ЭтоТекстSDBL = Истина) Экспорт
ФормаЗапроса = ПолучитьФорму("КонверторТекстаСУБД", , КлючУникальности);
ФормаЗапроса.ЭтоТекстSDBL = ЭтоТекстSDBL;
ФормаЗапроса.ЭлементыФормы.ТекстБД.УстановитьТекст(ТекстБД);
ФормаЗапроса.ПереводитьВМета = СразуПеревестиВМета;
ФормаЗапроса.Открыть();
Возврат Неопределено;
КонецФункции
Процедура ОткрытьПланЗапросаСУБДЛкс(Знач ПланЗапроса) Экспорт
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("sqlplan");
//СтандартнаяОбработка = Ложь;
Если ЗначениеЗаполнено(ПланЗапроса) Тогда
ПланЗапроса = ОтформатироватьТекстXML(ПланЗапроса);
Ответ = Вопрос("Перевести план запроса в термины метаданных?", РежимДиалогаВопрос.ДаНет,, КодВозвратаДиалога.Да);
Если Ответ = КодВозвратаДиалога.Да Тогда
ПланЗапроса = ирКэш.ПолучитьАнализТехножурналаЛкс().ПеревестиТекстБДВТерминыМетаданных(ПланЗапроса,,, "DBMSSQL",, 999999);
КонецЕсли;
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.УстановитьТекст(ПланЗапроса);
ТекстовыйДокумент.Записать(ИмяВременногоФайла);
ЗапуститьПриложение(ИмяВременногоФайла);
КонецЕсли;
КонецПроцедуры
Функция ОтформатироватьТекстXML(ТекстXML) Экспорт
Если Не ЗначениеЗаполнено(ТекстXML) Тогда
Возврат "";
КонецЕсли;
Дом = ирОбщий.ПрочитатьТекстВДокументDOMЛкс("<_>" + ТекстXML + "</_>");
ЗаписьXML = Новый ЗаписьXML;
ЗаписьДОМ = Новый ЗаписьDOM;
ОтформатированныйТекст = "";
Для Каждого ДочернийУзел Из ДОМ.ПервыйДочерний.ДочерниеУзлы Цикл
ЗаписьXML.УстановитьСтроку();
ЗаписьДОМ.Записать(ДочернийУзел, ЗаписьXML);
Если ОтформатированныйТекст <> "" Тогда
ОтформатированныйТекст = ОтформатированныйТекст + Символы.ПС;
КонецЕсли;
ОтформатированныйТекст = ОтформатированныйТекст + ЗаписьXML.Закрыть();
КонецЦикла;
Возврат ОтформатированныйТекст;
КонецФункции
Процедура ОткрытьНастройкуТехножурналаДляРегистрацииВыполненияЗапроса(Знач ТекстБД, ЭтоТекстSDBL = Ложь, ТипСУБД = Неопределено, ИмяБазы = "") Экспорт
Если Не ЭтоТекстSDBL Тогда
ТекстБД = ПолучитьТекстSQLДляПоискаВТехножурнале(ТекстБД);
КонецЕсли;
Если СтрДлина(ТекстБД) > 1000 Тогда
ТекстБД = Лев(ТекстБД , 1000) + "%";
КонецЕсли;
ТекстБД = ПолучитьШаблонТекстаБД(ТекстБД, "%");
ТекстБД = СтрЗаменить(ТекстБД, Символы.ПС, "%");
ТекстБД = СтрЗаменить(ТекстБД, "%%", "%");
ФормаНастройки = ирОбщий.ПолучитьФормуЛкс("Обработка.ирНастройкаТехножурнала.Форма");
ФормаНастройки.Открыть();
ФормаНастройки.НаСервере = Не ирКэш.Получить().ЭтоФайловаяБаза;
ФормаНастройки.ПриИзмененииПравилаПолученияФайлаНастройки();
Ответ = Вопрос("Хотите создать новую настройку?", РежимДиалогаВопрос.ДаНет);
Если Ответ = КодВозвратаДиалога.Да Тогда
ФормаНастройки.ЗагрузитьФайлНастройки("ШаблонЗаписьИсключительныхСитуаций", Истина, Истина, Ложь);
КонецЕсли;
СтрокаКаталога = ФормаНастройки.ТабличноеПолеЖурналы[0];
ФормаНастройки.ЭлементыФормы.ТабличноеПолеЖурналы.ТекущаяСтрока = СтрокаКаталога;
ФормаЖурнала = ФормаНастройки.ОткрытьФормуРедактированияЖурнала();
Если ЭтоТекстSDBL Тогда
УстановитьОтборПоСвойствуСобытияВФормеЖурнала(ФормаЖурнала, "SDBL", "sdbl", ТекстБД, , ИмяБазы);
Иначе
Если Не ЗначениеЗаполнено(ТипСУБД) Тогда
ВызватьИсключение "Для текста СУБД необходимо указать тип СУБД";
КонецЕсли;
УстановитьОтборПоСвойствуСобытияВФормеЖурнала(ФормаЖурнала, ТипСУБД, "sql", ТекстБД, , ИмяБазы);
КонецЕсли;
КонецПроцедуры
// Сравнение - Строка - как оно задается в настройке техножурнала (eq, ne, like и т.д.)
Процедура УстановитьОтборПоСвойствуСобытияВФормеЖурнала(ФормаЖурнала, ИмяСобытия, Знач ИмяСвойства, Знач ШаблонЗапроса, Сравнение = "like", Знач ИмяБазы = "") Экспорт
ТабличноеПолеСписокСобытий = ФормаЖурнала.ЭлементыФормы.ТабличноеПолеСписокСобытий;
ТабличноеПолеСписокСобытий.ВыделенныеСтроки.Очистить();
СтрокаСобытия = ФормаЖурнала.УстановитьРегистрациюСобытия(ИмяСобытия, Истина);
ТабличноеПолеСписокСобытий.ТекущаяСтрока = СтрокаСобытия;
ФормаЖурнала.УстановитьЭлементОтбораВВыделенныхГруппахИ(ИмяСвойства, ШаблонЗапроса, Сравнение);
Если Истина
И ЗначениеЗаполнено(ИмяБазы)
И Не ирКэш.ЛиФайловаяБазаЛкс()
Тогда
// К сожалению в файловой СУБД это свойство не заполняется
//ФормаЖурнала.КП_ДетальныйФильтрСобытийТекущаяБаза();
ФормаЖурнала.УстановитьЭлементОтбораВВыделенныхГруппахИ("p:processname", ИмяБазы);
КонецЕсли;
КонецПроцедуры
#КонецЕсли
Функция ПолучитьВариантПросмотраТекстПоИмениРеквизита(ИмяРеквизита) Экспорт
Если Ложь
Или мСвойстваСИменамиБД.Свойство(ПолучитьИмяСвойстваБезМета(ИмяРеквизита))
Или ирОбщий.СтрокиРавныЛкс(ИмяРеквизита, "ТекстЗапроса1С")
Тогда
ВариантПросмотра = "ЯзыкЗапросов";
ИначеЕсли ирОбщий.СтрокиРавныЛкс(ИмяРеквизита, "Контекст") <> Неопределено Тогда
ВариантПросмотра = "ВстроенныйЯзык";
Иначе
ВариантПросмотра = "Компактный";
КонецЕсли;
Возврат ВариантПросмотра;
КонецФункции
Функция ПреобразоватьЗначениеВSDBL(Ссылка) Экспорт
СтруктураБД = ирКэш.СтруктураХраненияБДЛкс(, мАдресЧужойСхемыБД);
Если ТипЗнч(Ссылка) = Тип("Строка") Тогда
Текст = "";
Иначе
СтруктураПоиска = Новый Структура("Метаданные, Назначение", Ссылка.Метаданные().ПолноеИмя(), "Основная");
СтрокаТаблицы = СтруктураБД.НайтиСтроки(СтруктураПоиска)[0];
RegExp = ирКэш.Получить().RegExp;
RegExp.Pattern = "\d+";
РезультатПоиска = RegExp.НайтиВхождения(СтрокаТаблицы.ИмяТаблицыХранения);
Текст = РезультатПоиска[0].Value + ":" + ирОбщий.ПолучитьГУИДИнверсныйИзПрямогоЛкс("" + Ссылка.УникальныйИдентификатор());
КонецЕсли;
Возврат Текст;
КонецФункции
Функция СтруктураЗапросаИзТекстаБД(ТекстБД, ТипСУБД = "", ПересобратьТекст = Ложь, ПеревестиИндексы = Истина, ПереводитьВМета = Истина, ЗаменитьHexЛитералы = Ложь,
ВстраиватьПараметры = Истина) Экспорт
Текст = ТекстБД;
//ТаблицаПараметров = Новый ТаблицаЗначений;
//ТаблицаПараметров.Колонки.Добавить("ЗначениеSDBL", Новый ОписаниеТипов("Строка"));
//ТаблицаПараметров.Колонки.Добавить("Значение");
//ТаблицаПараметров.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка"));
ТаблицаПараметров = ПараметрыЗапроса.ВыгрузитьКолонки();
ТаблицаПараметров.Индексы.Добавить("ЗначениеSDBL");
ТаблицаПараметров.Индексы.Добавить("Имя");
RegExp = мПлатформа.RegExp;
RegExp.Global = Истина;
RegExp.Multiline = Истина;
Если ЗначениеЗаполнено(ТипСУБД) Тогда
Если ПереводитьВМета Тогда
RegExp.Pattern = "TRef\s*=\s*(0x[\da-z]+)"; // замена обращений к типам
Вхождения = RegExp.НайтиВхождения(Текст);
ОбработанныеОбращения = Новый Соответствие;
Для Каждого Вхождение Из Вхождения Цикл
ЗначениеСУБД = Вхождение.Value;
Если ОбработанныеОбращения[ЗначениеСУБД] = Неопределено Тогда
ПолноеИмяМД = ирОбщий.МетаданныеПоНомеруСсылочнойТаблицыЛкс(ирОбщий.СтрокаHEXtoINTЛкс(Вхождение.SubMatches(0)), мАдресЧужойСхемыБД);
Если ПолноеИмяМД <> Неопределено Тогда
ЗаменаСтроки = "TRef = " + ПолноеИмяМД;
ОбработанныеОбращения[ЗначениеСУБД] = ЗаменаСтроки;
Текст = СтрЗаменить(Текст, ЗначениеСУБД, ЗаменаСтроки);
Иначе
ОбработанныеОбращения[ЗначениеСУБД] = 1;
КонецЕсли;
КонецЕсли;
КонецЦикла;
RegExp.Pattern = "^\s*\(@P\d+\s+\w+(?:\(\d+(?:,\d+)?\))?(,@P\d+\s+\w+(?:\(\d+(?:,\d+)?\))?)*\)"; // для удаления типов параметров MSSQL
Текст = RegExp.Заменить(Текст, "");
// sp_executesql
// {ОписаниеРегулярногоВыражения.Начало} конструктор из подсистемы "Инструменты разработчика" (http://devtool1c.ucoz.ru)
// Перем шЗначениеПараметра, шТипПараметра, шКорень;
// {Шаблон.Начало}
// + <шЗначениеПараметра> = (N?'([^']*)'|[^',]+)
// + <шТипПараметра> = @([\w]+) ([^']+?)(?='|$|,@)
// + <шКорень> = exec sp_executesql N'([^']+)',N'((?:<шТипПараметра>,)*<шТипПараметра>)'((?:,<шЗначениеПараметра>)+)
// {Шаблон.Конец}
шЗначениеПараметра = "(N?'([^']*)'|[^',]+)";
шТипПараметра = "@([\w]+) ([^']+?)(?='|$|,@)";
шКорень = "exec sp_executesql N'([^']+)',N'((?:" + шТипПараметра + ",)*" + шТипПараметра + ")'((?:," + шЗначениеПараметра + ")+)";
// {ОписаниеРегулярногоВыражения.Конец}
Вхождения = ирОбщий.НайтиРегулярноеВыражениеЛкс(Текст, шКорень, "ТекстЗапроса, ТипыПараметров", Ложь,,, Ложь);
#Если Сервер И Не Сервер Тогда
Вхождения = Обработки.ирПлатформа.Создать().ВхожденияРегВыражения;
#КонецЕсли
Для каждого Вхождение Из Вхождения Цикл
Текст = Вхождение.ТекстЗапроса;
ВложенныеВхождения = ирОбщий.НайтиРегулярноеВыражениеЛкс(Вхождение.ТипыПараметров, шТипПараметра, "Имя, Тип",,,, Ложь);
#Если Сервер И Не Сервер Тогда
Вхождения = Обработки.ирПлатформа.Создать().ВхожденияРегВыражения;
#КонецЕсли
Для каждого ВложенноеВхождение Из ВложенныеВхождения Цикл
СтрокаПараметра = ТаблицаПараметров.Добавить();
СтрокаПараметра.Имя = ВложенноеВхождение.Имя;
СтрокаПараметра.Метаданные = ВложенноеВхождение.Тип;
КонецЦикла;
ВложенныеВхождения = ирОбщий.НайтиРегулярноеВыражениеЛкс(Вхождение.Подгруппы[6], шЗначениеПараметра,,,,, Ложь);
#Если Сервер И Не Сервер Тогда
Вхождения = Обработки.ирПлатформа.Создать().ВхожденияРегВыражения;
#КонецЕсли
ИндексПараметра = 0;
Для каждого ВложенноеВхождение Из ВложенныеВхождения Цикл
СтрокаПараметра = ТаблицаПараметров[ИндексПараметра];
ИндексПараметра = ИндексПараметра + 1;
СтрокаПараметра.Значение = ВложенноеВхождение.ТекстВхождения;
КонецЦикла;
КонецЦикла;
КонецЕсли;
Иначе
RegExp.Pattern = "([A-F0-9]+):([A-F0-9]+|0x[A-F0-9]+)"; // замена ссылочных констант
Вхождения = RegExp.НайтиВхождения(Текст);
Для Каждого Вхождение Из Вхождения Цикл
ЗначениеSDBL = Вхождение.Value;
Если СтрДлина(ЗначениеSDBL) < 32 Тогда
// Защита от частей литерала Дата
Продолжить;
КонецЕсли;
Если ТаблицаПараметров.Найти(ЗначениеSDBL, "ЗначениеSDBL") = Неопределено Тогда
шЗначениеПараметра = ирОбщий.ПреобразоватьЗначениеИзSDBLЛкс(ЗначениеSDBL, мАдресЧужойСхемыБД, Истина);
СтрокаПараметра = ирОбщий.НайтиДобавитьПараметрСсылкуВТаблицуЛкс(ТаблицаПараметров,,, шЗначениеПараметра);
СтрокаПараметра.ЗначениеSDBL = ЗначениеSDBL;
ОбъектМД = ирОбщий.ПолучитьМетаданныеЛкс(шЗначениеПараметра);
Если ОбъектМД <> Неопределено Тогда
СтрокаПараметра.Метаданные = ОбъектМД.ПолноеИмя();
КонецЕсли;
Если ПереводитьВМета Тогда
Текст = СтрЗаменить(Текст, ЗначениеSDBL, "&" + СтрокаПараметра.Имя);
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если ЗаменитьHexЛитералы Тогда
RegExp.Pattern = "0x[\da-z]+"; // замена значений констант
Вхождения = RegExp.НайтиВхождения(Текст);
СоответствиеКонстант = Новый Соответствие;
Для Каждого Вхождение Из Вхождения Цикл
ЗначениеСУБД = Вхождение.Value;
Если СоответствиеКонстант[ЗначениеСУБД] = Неопределено Тогда
ЗаменаСтроки = "_" + ЗначениеСУБД;
СоответствиеКонстант[ЗначениеСУБД] = ЗаменаСтроки;
Текст = СтрЗаменить(Текст, ЗначениеСУБД, ЗаменаСтроки);
КонецЕсли;
КонецЦикла;
КонецЕсли;
//RegExp.Pattern = "#(T[\d_A-Z]+)"; // имена временных таблиц
//Текст = RegExp.Заменить(Текст, "_$1");
RegExp.Pattern = "\{ts '(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)'\}"; // литералы Дата DBV8DBEng
Текст = RegExp.Заменить(Текст, "DATETIME($1,$2,$3,$4,$5,$6)");
ТаблицаТаблиц = Новый ТаблицаЗначений;
Если ПереводитьВМета Тогда
RegExp.Pattern = "N'([^']*)'"; // для замены юникодных литералов типа Строка MSSQL
Текст = RegExp.Заменить(Текст, """$1""");
КонецЕсли;
ТекстМета = ПеревестиТекстБДВТерминыМетаданных(Текст,,, ТипСУБД, ТаблицаТаблиц, 999999, ПеревестиИндексы, ПереводитьВМета);
Если Не ПереводитьВМета Тогда
ТекстМета = Текст;
КонецЕсли;
ТаблицаТаблиц.Сортировать("ИмяМета");
ЧастьПараметров = "";
Если ЗначениеЗаполнено(ТипСУБД) Тогда
ДиалектSQL = "MSSQL";
ПозицияНачалаПараметров = Найти(ТекстМета, "p_0:");
Если ПозицияНачалаПараметров > 0 Тогда
ЧастьПараметров = Сред(ТекстМета, ПозицияНачалаПараметров);
ТекстМета = Лев(ТекстМета, ПозицияНачалаПараметров - 1);
КонецЕсли;
Иначе
ДиалектSQL = "1С";
КонецЕсли;
ШаблонИмениПараметра = "Parameter";
Если ЗначениеЗаполнено(ЧастьПараметров) Тогда
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.УстановитьТекст(ЧастьПараметров);
Для Счетчик = 1 По ТекстовыйДокумент.КоличествоСтрок() Цикл
СтрокаПараметра = ТаблицаПараметров.Добавить();
Фрагменты = ирОбщий.СтрРазделитьЛкс(ТекстовыйДокумент.ПолучитьСтроку(Счетчик), ":");
СтрокаПараметра.Имя = СокрЛП(Фрагменты[0]);
СтрокаПараметра.Значение = СокрЛП(Фрагменты[1]);
КонецЦикла;
КонецЕсли;
МаркерСтрокиВРодномMSSQL = "N'";
МаркерБинариВРодномMSSQL = "0x";
Для Каждого СтрокаПараметра Из ТаблицаПараметров Цикл
Если ТипСУБД = "DBMSSQL" Тогда
ЛитералЗначения = СтрокаПараметра.Значение;
Если ЗначениеЗаполнено(СтрокаПараметра.Метаданные) Тогда
// ТипСобытия = sp_executesql
Если ирОбщий.СтрНачинаетсяСЛкс(ЛитералЗначения, МаркерСтрокиВРодномMSSQL) Тогда
ЛитералЗначения = ирОбщий.СтрокаБезКонцаЛкс(Сред(ЛитералЗначения, СтрДлина(МаркерСтрокиВРодномMSSQL) + 1), 1);
СтрокаПараметра.Значение1С = ЛитералЗначения;
ИначеЕсли ирОбщий.СтрНачинаетсяСЛкс(ЛитералЗначения, "'") Тогда
ЛитералЗначения = ирОбщий.СтрокаБезКонцаЛкс(Сред(ЛитералЗначения, 2), 1);
Попытка
СтрокаПараметра.Значение1С = ирОбщий.СтрокаВДатуЛкс(ЛитералЗначения);
Исключение
Пустышка = 0;
КонецПопытки;
Иначе
Попытка
СтрокаПараметра.Значение1С = Число(ЛитералЗначения);
Исключение
КонецПопытки;
КонецЕсли;
Иначе
// ТипСобытия = DBMSSQL
Если Прав(ЛитералЗначения, 1) = "N" Тогда
ЛитералЗначения = ирОбщий.СтрокаБезКонцаЛкс(ЛитералЗначения, 1);
Попытка
СтрокаПараметра.Значение1С = Число(ЛитералЗначения);
СтрокаПараметра.Метаданные = Тип("Число");
Исключение
Пустышка = 0;
КонецПопытки;
ИначеЕсли Лев(ЛитералЗначения, 1) = "'" Тогда
СтрокаПараметра.Значение1С = Сред(ирОбщий.СтрокаБезКонцаЛкс(ЛитералЗначения, 1), 2);
СтрокаПараметра.Метаданные = Тип("Строка");
ИначеЕсли СтрДлина(ЛитералЗначения) = СтрДлина("20010101000000") Тогда
ЛитералЗначения = "" + (Число(Лев(ЛитералЗначения, 1)) - 2) + Сред(ЛитералЗначения, 2);
Попытка
СтрокаПараметра.Значение1С = Дата(ЛитералЗначения);
СтрокаПараметра.Метаданные = Тип("Дата");
Исключение
Пустышка = 0;
КонецПопытки;
Иначе
СтрокаПараметра.Значение1С = ЛитералЗначения;
СтрокаПараметра.Метаданные = Тип("ДвоичныеДанные");
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Встроим имена парамаетров вместо знаков "?"
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку("");
ИндексПараметра = 0;
СтрокаПоиска = "?";
Пока ТекстМета <> "" Цикл
ПозицияПараметра = Найти(ТекстМета, СтрокаПоиска);
Если ПозицияПараметра > 0 Тогда
Если ИндексПараметра < ТаблицаПараметров.Количество() Тогда
СтрокаПараметра = ТаблицаПараметров[ИндексПараметра];
Иначе
СтрокаПараметра = ТаблицаПараметров.Добавить();
СтрокаПараметра.Имя = ШаблонИмениПараметра + XMLСтрока(ТаблицаПараметров.Количество());
КонецЕсли;
ЗаписьXML.ЗаписатьБезОбработки(Лев(ТекстМета, ПозицияПараметра - 1) + СтрокаПоиска + СтрокаПараметра.Имя);
ТекстМета = Сред(ТекстМета, ПозицияПараметра + СтрДлина(СтрокаПоиска));
ИндексПараметра = ИндексПараметра + 1;
Иначе
ЗаписьXML.ЗаписатьБезОбработки(ТекстМета);
ТекстМета = "";
КонецЕсли;
КонецЦикла;
ТекстМета = ЗаписьXML.Закрыть();
Если Истина
И ПересобратьТекст
И ЗначениеЗаполнено(ТекстМета)
Тогда
ПолеТекста = ирОбщий.СоздатьОбъектПоПолномуИмениМетаданныхЛкс("Обработка.ирКлсПолеТекстаПрограммы");
ПолеТекста.ИнициализироватьНеинтерактивно(1);
КонструкторЗапроса = ПолеТекста.ПолучитьФорму("КонструкторЗапроса");
КонструкторЗапроса.Английский1С = Не ПереводитьВМета;
ИменованныеПараметры = Истина;
Если ПолеТекста.ЗагрузитьТекстВКонструктор(ТекстМета, КонструкторЗапроса,, ДиалектSQL, ИменованныеПараметры) Тогда
ТекстМета = КонструкторЗапроса.СобратьПолныйТекст(, Истина);
КонецЕсли;
КонецЕсли;
Если ВстраиватьПараметры Тогда
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку("");
ИндексПараметра = 0;
Пока ТекстМета <> "" Цикл
ПозицияПараметра = 0;
Если ИндексПараметра < ТаблицаПараметров.Количество() Тогда
СтрокаПоиска = "?" + ТаблицаПараметров[ИндексПараметра].Имя;
ПозицияПараметра = Найти(ТекстМета, СтрокаПоиска);
КонецЕсли;
Если Истина
И ПозицияПараметра > 0
Тогда
ЗаписьXML.ЗаписатьБезОбработки(Лев(ТекстМета, ПозицияПараметра - 1) + ТаблицаПараметров[ИндексПараметра].Значение);
ИндексПараметра = ИндексПараметра + 1;
ТекстМета = Сред(ТекстМета, ПозицияПараметра + СтрДлина(СтрокаПоиска));
Иначе
ЗаписьXML.ЗаписатьБезОбработки(ТекстМета);
ТекстМета = "";
КонецЕсли;
КонецЦикла;
ТекстМета = ЗаписьXML.Закрыть();
КонецЕсли;
Результат = Новый Структура();
Результат.Вставить("Текст", ТекстМета);
Результат.Вставить("Параметры", ТаблицаПараметров);
Результат.Вставить("Таблицы", ТаблицаТаблиц);
Возврат Результат;
КонецФункции
Функция НайтиВызовыМетодовМодулей(ИмяМодуля, НомерНачальнойСтроки, НомерКонечнойСтроки, ТолькоОдну = Истина)
Результат = Новый Массив();
Для Каждого СтрокаТаблицы Из ТаблицаЖурнала Цикл
ФрагментыНачальнойСтрокиМодуля = ирОбщий.СтрРазделитьЛкс(СтрокаТаблицы.СтрокаМодуля, ":", Истина);
Если ФрагментыНачальнойСтрокиМодуля[0] <> ИмяМодуля Тогда
Результат.Вставить(0, СтрокаТаблицы);
Если ТолькоОдну Тогда
Прервать;
КонецЕсли;
КонецЕсли;
НомерСтрокиМодуля = Число(ФрагментыНачальнойСтрокиМодуля[1]);
Если Ложь
Или НомерСтрокиМодуля < НомерНачальнойСтроки
Или НомерСтрокиМодуля > НомерКонечнойСтроки
Тогда
Результат.Вставить(0, СтрокаТаблицы);
Если ТолькоОдну Тогда
Прервать;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
// Получить словарь имен таблиц входящих в запрос и соответствующих
// шаблонам словаря метаданных
//
// Параметры:
// ТекстЗапроса - Строка, текст запроса для которого строится словарь
// СловарьШаблоновМетаданных - Соответствие, словарь шаблонов метаданных
// ТипСУБД - Строка (Перечисление.ТипСУБД)
//
// Возвращаемое значение:
// Соответствие - Словарь имен таблиц запроса
//
Функция ИменаМетаданныхЗапросаСУБД(Знач ТекстЗапроса, СловарьШаблоновМетаданных, ТипСУБД = "") Экспорт
Результат = Новый ТаблицаЗначений;
Результат.Колонки.Добавить("Имя");
Результат.Колонки.Добавить("Длина");
ТекстЗапроса = НРег(ТекстЗапроса);
//Если НРег(ТипСУБД) = НРег("DB2") Тогда
// ТекстЗапроса = ВРег(ТекстЗапроса);
//КонецЕсли;
Для Каждого СтрокаСловаряМетаданных Из СловарьШаблоновМетаданных Цикл
ТаблицаВхождений = ирОбщий.НайтиРегулярноеВыражениеЛкс(ТекстЗапроса, СтрокаСловаряМетаданных.РегулярныйШаблон,,,,,, Истина);
#Если Сервер И Не Сервер Тогда
ТаблицаВхождений = Обработки.ирПлатформа.Создать().ВхожденияРегВыражения;
#КонецЕсли
Для Каждого СтрокаВхождения Из ТаблицаВхождений Цикл
НоваяСтрока = Результат.Добавить();
НоваяСтрока.Имя = СтрокаВхождения.ТекстВхождения;
НоваяСтрока.Длина = СтрДлина(НоваяСтрока.Имя);
КонецЦикла;
КонецЦикла;
Результат.Сортировать("Длина Убыв");
Результат.Свернуть("Имя");
Возврат Результат;
КонецФункции // ПолучитьСловарьЗапроса()
// Получить число из строки в которой число находится в начале строки
//
// Праметры:
// ИсходнаяСтрока - Строка, строка в которой находится число
//
// Возвращаемое значение:
// Число - если оно есть, неопределено, если числа нет
//
Функция ПолучитьЧислоСтрокой(ИсходнаяСтрока, КоличествоСимволов)
КоличествоСимволов = 0;
ДлинаСтроки = СтрДлина(ИсходнаяСтрока);
Для Сч = 1 По ДлинаСтроки Цикл
ТекущийСимвол = КодСимвола(Сред(ИсходнаяСтрока, Сч, 1));
Если 48 <= ТекущийСимвол И ТекущийСимвол <= 57 Тогда
КоличествоСимволов = КоличествоСимволов + 1;
Иначе
Прервать;
КонецЕсли;
КонецЦикла;
Если КоличествоСимволов > 0 Тогда
Возврат Лев(ИсходнаяСтрока, КоличествоСимволов);
Иначе
Возврат Неопределено;
КонецЕсли;
КонецФункции // ПолучитьЧислоСтрокой()
// Перевести часть запроса из терминов СУБД в термины метаданных
//
// Параметры:
// Запрос - Строка, сапрос в терминах СУБД
// СтруктураХраненияБазыДанных - ТаблицаЗначений
// СловарьШаблоновМетаданных - Соответствие, подробности в функции
// ПолучитьСловарьШаблоновМетаданных()
// ТипСУБД - Строка, (Перечисление.ТипСУБД)
// выхТаблицы - ТаблицаЗначений, *Неопределено - описание использованных в тексте таблиц, заполняется только если таблица передана (без колонок)
//
// Возвращаемое значение:
// Строка, запрос в терминах метаданных
//
Функция ПеревестиТекстБДВТерминыМетаданных(Знач Текст, СтруктураХраненияБазыДанных = Неопределено,
СловарьШаблоновМетаданных = Неопределено, Знач ТипСУБД = "", выхТаблицы = Неопределено, ДопустимыйРазмер = 20000, ПереводитьИндексы = Истина, ПереводитьВМета = Истина,
ЭтоГарантированоТекстСобственнойБазы = Ложь) Экспорт
Если выхТаблицы <> Неопределено Тогда
#Если Сервер И Не Сервер Тогда
выхТаблицы = Новый ТаблицаЗначений;
#КонецЕсли
//выхТаблицы.Колонки.Очистить();
Если выхТаблицы.Колонки.Найти("ИмяБД") = Неопределено Тогда
выхТаблицы.Колонки.Добавить("ИмяБД", Новый ОписаниеТипов("Строка"));
КонецЕсли;
Если выхТаблицы.Колонки.Найти("ИмяМета") = Неопределено Тогда
выхТаблицы.Колонки.Добавить("ИмяМета", Новый ОписаниеТипов("Строка"));
КонецЕсли;
КонецЕсли;
Если Ложь
Или Не ЗначениеЗаполнено(Текст)
Тогда
Возврат "";
КонецЕсли;
Если Истина
И ДопустимыйРазмер > 0
И СтрДлина(Текст) > ДопустимыйРазмер
И ПереводитьВМета
Тогда
Возврат РезультатПереводаСлишкомБольшогоТекста();
КонецЕсли;
Если ирОбщий.СтрокиРавныЛкс(ТипСУБД, "sdbl") Тогда
ТипСУБД = "";
КонецЕсли;
АдресЧужойСхемыБД = "";
Если Не ЭтоГарантированоТекстСобственнойБазы Тогда
АдресЧужойСхемыБД = мАдресЧужойСхемыБД;
КонецЕсли;
Если СтруктураХраненияБазыДанных = Неопределено Тогда
СтруктураХраненияБазыДанных = ирКэш.СтруктураХраненияБДЛкс(ЗначениеЗаполнено(ТипСУБД), АдресЧужойСхемыБД);
КонецЕсли;
Если СловарьШаблоновМетаданных = Неопределено Тогда
СловарьШаблоновМетаданных = ирКэш.ПолучитьСловарьШаблоновМетаданныхЛкс(ЗначениеЗаполнено(ТипСУБД), АдресЧужойСхемыБД);
КонецЕсли;
Текст = Текст + Символы.ПС;
ИменаМетаданныхЗапроса = ИменаМетаданныхЗапросаСУБД(Текст, СловарьШаблоновМетаданных, ТипСУБД);
Если НРег(ТипСУБД) = НРег("DB2") Тогда
Текст = ВРег(Текст);
КонецЕсли;
// Поиск имен таблиц в строке запроса
Если ИменаМетаданныхЗапроса.Количество() > 10 Тогда
Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ИменаМетаданныхЗапроса.Количество(), "Преобразование в имена метаданных");
КонецЕсли;
Для Каждого ИмяМетаданного Из ИменаМетаданныхЗапроса Цикл
Если Индикатор <> Неопределено Тогда
ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
КонецЕсли;
ОписаниеТаблицы = Неопределено;
Если выхТаблицы <> Неопределено Тогда
Если Найти(ИмяМетаданного.Имя, ".") = 0 Тогда
ОписаниеТаблицы = выхТаблицы.Добавить();
ОписаниеТаблицы.ИмяБД = ИмяМетаданного.Имя;
КонецЕсли;
КонецЕсли;
// Получить имя таблицы
СтрокаСтруктуры = СтруктураХраненияБазыДанных.Найти(ирОбщий.ПоследнийФрагментЛкс(ИмяМетаданного.Имя), "КраткоеИмяТаблицыХранения");
Если СтрокаСтруктуры = Неопределено Тогда
// Видимо чужие метаданные
Продолжить;
КонецЕсли;
ИмяТаблицы = СтрокаСтруктуры.КраткоеИмяТаблицыХранения;
МетаПолноеИмяТаблицы = СтрокаСтруктуры.ИмяТаблицы;
Если ОписаниеТаблицы <> Неопределено Тогда
ОписаниеТаблицы.ИмяМета = МетаПолноеИмяТаблицы;
КонецЕсли;
Если Не ПереводитьВМета Тогда
Продолжить;
КонецЕсли;
Синонимы = ПолучитьСинонимы(Текст, ИмяТаблицы, МетаПолноеИмяТаблицы, ТипСУБД);
//Синонимы.Вставить(ИмяТаблицы, МетаИмяТаблицы);
ЭтоТабличнаяЧасть = СтрокаСтруктуры.Назначение = "ТабличнаяЧасть";
Для Каждого СтрокаПоля Из СтрокаСтруктуры.Поля Цикл
Если Найти(Текст, СтрокаПоля.ИмяПоляХранения) = 0 Тогда
Продолжить;
КонецЕсли;
ПредставлениеПоля = ирОбщий.ПредставлениеПоляБДЛкс(СтрокаПоля, ТипСУБД <> "", ЭтоТабличнаяЧасть);
Если Не ЗначениеЗаполнено(ПредставлениеПоля) Тогда
Продолжить;
КонецЕсли;
RegExpМета.Pattern = шГраничныйСимволИмени + СтрокаПоля.ИмяПоляХранения + "([^&" + шБуква + "\d]|Balance|Turnover|Receipt|Expense|^|$)";
// Можно оптимизировать путем создания шаблона мультизамены
Текст = RegExpМета.Заменить(Текст, "$1" + ПредставлениеПоля + "$2");
КонецЦикла;
Если ПереводитьИндексы Тогда
Для Каждого СтрокаИндекса Из СтрокаСтруктуры.Индексы Цикл
ирОбщий.ЗаполнитьИмяИндексаХраненияЛкс(СтрокаИндекса, ТипСУБД <> "", СтрокаСтруктуры);
ПредставлениеИндекса = СтрокаИндекса.ИмяИндекса;
СтрокаДляЗамены = СтрокаИндекса.ИмяИндексаХранения;
Если ирОбщий.СтрокиРавныЛкс(ТипСУБД, "DBPOSTGRS") Тогда
СтрокаДляЗамены = ВРег(СтрокаИндекса.ИмяИндексаХранения);
ИначеЕсли ирОбщий.СтрокиРавныЛкс(ТипСУБД, "DBV8DBEng") Тогда
СтрокаДляЗамены = ВРег(СтрокаИндекса.ИмяИндексаХранения);
КонецЕсли;
// Имена индексов достаточно уникальны, чтобы использовать СтрЗаменить
Текст = СтрЗаменить(Текст, СтрокаДляЗамены, ПредставлениеИндекса);
КонецЦикла;
КонецЕсли;
Для Каждого Синоним Из Синонимы Цикл
// Заменить псевдоним таблицы
RegExpМета.Pattern = шГраничныйСимволИмени + Синоним.Ключ + шГраничныйСимволИмени;
Текст = RegExpМета.Заменить(Текст, "$1" + Синоним.Значение + "$2");
//RegExpМета.Pattern = ИмяТаблицы + " " + Синоним.Ключ + шГраничныйСимволИмени;
//Запрос = RegExpМета.Заменить(Текст, ИмяТаблицы + " AS " + Синоним.Значение + "$1");
КонецЦикла;
// Заменить имя таблицы
RegExpМета.Pattern = шГраничныйСимволИмени + СтрокаСтруктуры.ИмяТаблицыХранения + шГраничныйСимволИмени;
Текст = RegExpМета.Заменить(Текст, "$1" + МетаПолноеИмяТаблицы + "$2");
Если НРег(СтрокаСтруктуры.ИмяТаблицыХранения) <> СтрокаСтруктуры.КраткоеИмяТаблицыХранения Тогда
RegExpМета.Pattern = шГраничныйСимволИмени + СтрокаСтруктуры.КраткоеИмяТаблицыХранения + шГраничныйСимволИмени;
Текст = RegExpМета.Заменить(Текст, "$1" + ирОбщий.ПоследнийФрагментЛкс(МетаПолноеИмяТаблицы) + "$2");
КонецЕсли;
КонецЦикла;
Если Индикатор <> Неопределено Тогда
ирОбщий.ОсвободитьИндикаторПроцессаЛкс(Индикатор);
КонецЕсли;
// Заменим приведение к ссылочному типу
Если Не ЗначениеЗаполнено(ТипСУБД) Тогда
Текст = СтрЗаменить(Текст, "AS REF(", "AS (");
КонецЕсли;
Текст = СокрП(Текст);
Возврат Текст;
КонецФункции
Функция РезультатПереводаСлишкомБольшогоТекста() Экспорт
Возврат "<Текст слишком большой для быстрого перевода>"
КонецФункции
// Получить синонимы имени таблицы в запросе
//
// Параметры:
// Запрос - Строка, текст запроса
// ИмяТаблицы - Строка, имя таблицы для которой ищутся синонимы
// МетаИмяТаблицы - Строка, имя таблицы в терминах метаданных
//
// Возвращаемое занчение:
// Соответствие, имена синонимов и их мета имена
//
Функция ПолучитьСинонимы(Запрос, ИмяТаблицы, МетаИмяТаблицы, ТипСУБД = "") Экспорт
// Построить список синонимом ими таблицы
Синонимы = Новый Соответствие;
RegExpМета.Pattern = ИмяТаблицы + " " + "(?:([" + шБуква + "\d]+)|\(([" + шБуква + "\d]+)\))" + шГраничныйСимволИмени;
Вхождения = RegExpМета.НайтиВхождения(Запрос);
ПсевдонимТаблицы = ирОбщий.ПоследнийФрагментЛкс(МетаИмяТаблицы, ".");
Для Каждого Вхождение Из Вхождения Цикл
Синоним = Вхождение.SubMatches(0);
Если Синоним = Неопределено Тогда
Синоним = Вхождение.SubMatches(1);
КонецЕсли;
Если Ложь
Или (Истина
И ирОбщий.СтрокиРавныЛкс(ТипСУБД, "DBMSSQL")
И ирОбщий.СтрокиРавныЛкс(Синоним, "WITH"))
Или ирОбщий.СтрокиРавныЛкс(Синоним, "WHERE")
Или ирОбщий.СтрокиРавныЛкс(Синоним, "GROUP")
Или ирОбщий.СтрокиРавныЛкс(Синоним, "HAVING")
Или ирОбщий.СтрокиРавныЛкс(Синоним, "SET")
Или ирОбщий.СтрокиРавныЛкс(Синоним, "ORDER")
Или ирОбщий.СтрокиРавныЛкс(Синоним, "THEN")
Тогда
Продолжить;
КонецЕсли;
Синонимы.Вставить(Синоним, ПсевдонимТаблицы + "_" + Синоним);
КонецЦикла;
Возврат Синонимы;
КонецФункции // ПолучитьСинонимы()
//ирПортативный лФайл = Новый Файл(ИспользуемоеИмяФайла);
//ирПортативный ПолноеИмяФайлаБазовогоМодуля = Лев(лФайл.Путь, СтрДлина(лФайл.Путь) - СтрДлина("Модули\")) + "ирПортативный.epf";
//ирПортативный #Если Клиент Тогда
//ирПортативный Контейнер = Новый Структура();
//ирПортативный Оповестить("ирПолучитьБазовуюФорму", Контейнер);
//ирПортативный Если Не Контейнер.Свойство("ирПортативный", ирПортативный) Тогда
//ирПортативный ирПортативный = ВнешниеОбработки.ПолучитьФорму(ПолноеИмяФайлаБазовогоМодуля);
//ирПортативный ирПортативный.Открыть();
//ирПортативный КонецЕсли;
//ирПортативный #Иначе
//ирПортативный ирПортативный = ВнешниеОбработки.Создать(ПолноеИмяФайлаБазовогоМодуля, Ложь); // Это будет второй экземпляр объекта
//ирПортативный #КонецЕсли
//ирПортативный ирОбщий = ирПортативный.ПолучитьОбщийМодульЛкс("ирОбщий");
//ирПортативный ирКэш = ирПортативный.ПолучитьОбщийМодульЛкс("ирКэш");
//ирПортативный ирСервер = ирПортативный.ПолучитьОбщийМодульЛкс("ирСервер");
//ирПортативный ирПривилегированный = ирПортативный.ПолучитьОбщийМодульЛкс("ирПривилегированный");
мПлатформа = ирКэш.Получить();
ЭтотОбъект.КоличествоПотоков = 8;
мНепустыеКолонкиЖурнала = Новый Структура();
//ЭтотОбъект.НаложениеПриДозагрузкеСекунд = 30;
RegExpПараметры = ирОбщий.НовыйВычислительРегВыражений();
Если RegExpПараметры <> Неопределено Тогда
RegExpПараметры.IgnoreCase = Истина;
RegExpПараметры.Global = Истина;
RegExpПараметры.Pattern = "([^A-ZА-ЯЁ_0-9]|^)(?:[A-F0-9]+:[A-F0-9]+|0x[A-F0-9]+|[A-F0-9]+(?:-[A-F0-9]+)+-[A-F0-9]+|(#TT?)[_A-F0-9]+|[0-9]+)"; // для стирания констант и имен временных таблиц
RegExpМета = ирОбщий.НовыйВычислительРегВыражений();
RegExpМета.IgnoreCase = Истина;
RegExpМета.Global = Истина;
КонецЕсли;
мСписокКолонок = Новый СписокЗначений;
//мСписокКолонок.Добавить("Name", "Событие"); // В некоторых случаях нужно
мСписокКолонок.Добавить("SrcName", "Источник");
мСписокКолонок.Добавить("OSThread", "ПотокОС");
мСписокКолонок.Добавить("process", "ТипПроцессаОС");
мСписокКолонок.Добавить("p:processName", "Инфобаза");
мСписокКолонок.Добавить("t:clientID", "Соединение_");
мСписокКолонок.Добавить("t:applicationName", "Приложение");
мСписокКолонок.Добавить("t:computerName", "Компьютер");
мСписокКолонок.Добавить("t:connectID", "TCPСоединение");
мСписокКолонок.Добавить("SessionID", "Сеанс");
мСписокКолонок.Добавить("Usr", "Пользователь");
мСписокКолонок.Добавить("OSException", "ИсключениеОС");
мСписокКолонок.Добавить("Interface", "Интерфейс");
мСписокКолонок.Добавить("Method", "Метод");
мСписокКолонок.Добавить("Exception", "ТипИсключения");
мСписокКолонок.Добавить("Descr", "Описание");
мСписокКолонок.Добавить("ClientComputerName", "КомпьютерКлиента");
мСписокКолонок.Добавить("ServerComputerName", "КомпьютерСервера");
мСписокКолонок.Добавить("UserName", "Пользователь");
мСписокКолонок.Добавить("ConnectString", "СтрокаСоединения");
мСписокКолонок.Добавить("ProcessName", "ТипПроцессаОС");
мСписокКолонок.Добавить("SrcProcessName", "Инфобаза");
//мСписокКолонок.Добавить("Trans", "Транзакция");
мСписокКолонок.Добавить("Func", "Действие");
мСписокКолонок.Добавить("Sdbl", "ТекстSDBL");
мСписокКолонок.Добавить("dbpid", "ПроцессСУБД");
мСписокКолонок.Добавить("Sql", "ТекстСУБД");
мСписокКолонок.Добавить("NParams", "КоличествоПараметров");
мСписокКолонок.Добавить("Rows", "ЧислоСтрок");
мСписокКолонок.Добавить("RowsAffected", "ЧислоИзменныхСтрок");
мСписокКолонок.Добавить("planSQLText", "ПланСУБД");
мСписокКолонок.Добавить("Context", "Контекст");
мСписокКолонок.Добавить("CatName", "КаталогСУБД");
мСписокКолонок.Добавить("WaitConnections", "Блокираторы");
мСписокКолонок.Добавить("FileName", "ФайлСУБД");
мСписокКолонок.Добавить("DeadlockConnectionIntersections", "Взаимоблокировка");
мСписокКолонок.Добавить("Finish", "ПричинаЗавершения");
мСписокКолонок.Добавить("Err", "ТипСообщения");
мСписокКолонок.Добавить("Txt", "ТекстСообщения");
мСписокКолонок.Добавить("URI", "Ресурс");
мСписокКолонок.Добавить("Administrator", "Администратор");
мСписокКолонок.Добавить("Body", "РазмерЗапроса");
мСписокКолонок.Добавить("Cluster", "НомерПорта");
мСписокКолонок.Добавить("Val", "ЗначениеПараметра");
// Свойства найденные экспериментально. Они не документированы.
мСписокКолонок.Добавить("Query", "ТекстЗапроса1С"); // События: QERR
мСписокКолонок.Добавить("From", "From_"); // События: DBV8DBENG
//мСписокКолонок.Добавить("AppID", "AppID"); // События: QERR, DBMSSQL (дублируется t:applicationName), SDBL (дублирует t:applicationName)
мСписокКолонок.Добавить("Index", "Index_");
//мСписокКолонок.Добавить("setUnhandledExceptionFilter", "setUnhandledExceptionFilter");
мСписокКолонок.Добавить("Module", "МодульКонфигурации"); // События: EXCPCNTX
мСписокКолонок.Добавить("ClientID", "Клиент"); // События: EXCPCNTX, SCALL, EXCP (дублируется t:clientID ?)
мТаблицаКолонок = Новый ТаблицаЗначений;
мТаблицаКолонок.Колонки.Добавить("ВнутреннееИмя", Новый ОписаниеТипов("Строка"));
мТаблицаКолонок.Колонки.Добавить("ИмяВТаблице", Новый ОписаниеТипов("Строка"));
мТаблицаКолонок.Индексы.Добавить("ВнутреннееИмя");
мТаблицаКолонок.Индексы.Добавить("ИмяВТаблице");
//мЧисловыеСвойства = Новый Структура;
мСоответствиеКолонок = Новый Соответствие;
МетаРеквизиты = Метаданные().ТабличныеЧасти.ТаблицаЖурнала.Реквизиты;
Для Каждого ЭлементСписка Из мСписокКолонок Цикл
мСоответствиеКолонок.Вставить(НРег(ЭлементСписка.Значение), ЭлементСписка.Представление);
СтрокаСоответствия = мТаблицаКолонок.Добавить();
СтрокаСоответствия.ВнутреннееИмя = ЭлементСписка.Значение;
СтрокаСоответствия.ИмяВТаблице = ЭлементСписка.Представление;
//Если МетаРеквизиты[ЭлементСписка.Представление].Тип.СодержитТип(Тип("Число")) Тогда
// мЧисловыеСвойства.Вставить(ЭлементСписка.Представление);
//КонецЕсли;
КонецЦикла;
Для Каждого МетаРеквизит Из МетаРеквизиты Цикл
Если мСоответствиеКолонок[МетаРеквизит.Имя] = Неопределено Тогда
мСоответствиеКолонок.Вставить(НРег(МетаРеквизит.Имя), МетаРеквизит.Имя);
КонецЕсли;
КонецЦикла;
мКартыФайлов = Новый ТаблицаЗначений;
мКартыФайлов.Колонки.Добавить("ИмяКаталогаПроцесса", Новый ОписаниеТипов("Строка"));
мКартыФайлов.Колонки.Добавить("ИмяТекущегоФайла", Новый ОписаниеТипов("Строка"));
мКартыФайлов.Колонки.Добавить("СигнатураТекущегоФайла", Новый ОписаниеТипов("Строка"));
мКартыФайлов.Колонки.Добавить("ОтборПоСеансу");
мКартыФайлов.Колонки.Добавить("ПозицияНачала", Новый ОписаниеТипов("Число"));
мКартыФайлов.Колонки.Добавить("ПозицияКонца", Новый ОписаниеТипов("Число"));
мКартыФайлов.Колонки.Добавить("НачалоПериода", Новый ОписаниеТипов("Дата"));
мКартыФайлов.Колонки.Добавить("КонецПериода", Новый ОписаниеТипов("Дата"));
мКартыФайлов.Колонки.Добавить("ДатаИзмененияФайла", Новый ОписаниеТипов("Дата"));
мКартыФайлов.Индексы.Добавить("ИмяКаталогаПроцесса, ИмяТекущегоФайла, СигнатураТекущегоФайла, ОтборПоСеансу");
мСвойстваСИменамиБД = Новый Структура();
мСвойстваСИменамиБД.Вставить("ТекстSDBL", Ложь);
мСвойстваСИменамиБД.Вставить("ТекстSDBLШаблон", Ложь);
мСвойстваСИменамиБД.Вставить("ТекстСУБД", Истина);
мСвойстваСИменамиБД.Вставить("ТекстСУБДШаблон", Ложь);
мСвойстваСИменамиБД.Вставить("ПланСУБД", Истина);
мСвойстваСИменамиБД.Вставить("Взаимоблокировка", Ложь);
мСвойстваСИменамиБД.Вставить("Regions", Ложь);
мСвойстваСИменамиБД.Вставить("Locks", Ложь);
мСерверныеТипыПроцессов = Новый Структура;
мСерверныеТипыПроцессов.Вставить("_adminprocess"); // ##AdminProcess##
мСерверныеТипыПроцессов.Вставить("_rphost");
мСерверныеТипыПроцессов.Вставить("_rmngr");
мСерверныеТипыПроцессов.Вставить("_ragent");
мЛиТрассаПоПользователю = Ложь;
МаксТысячСобытий = 100;
мАдресЧужойСхемыБД = "";
шБуква = мПлатформа.шБуква;
шГраничныйСимволИмени = "([^&" + шБуква + "\d]|^|$)";
мИменаВозвращаемыхСвойств = "мКартыФайлов, мНепустыеКолонкиЖурнала, мТипСУБД";
мТаблицаЖурнала = ТаблицаЖурнала;
#Если Не Клиент Тогда
мТаблицаЖурнала = мТаблицаЖурнала.ВыгрузитьКолонки();
#КонецЕсли