При работе со старыми, но критически важными информационными системами на платформе 1С:Предприятие 7.7 (SQL-версия) администраторы и разработчики иногда сталкиваются с внезапными и критическими сбоями платформы. Один из наиболее неприятных симптомов — аварийное завершение работы программы (ошибка APPCRASH приложения 1cv7s.exe в модуле BkEnd.dll) при обычном скроллинге (прокрутке) журнала документов.
В этой статье мы подробно разберем внутренние механизмы СУБД MS SQL Server и платформы 1С 7.7, выясним первопричину этой проблемы, научимся ее диагностировать и рассмотрим самый безопасный способ решения без риска потери данных.
Для того чтобы понять физику процесса, нам необходимо обратиться к архитектуре хранения данных 1С 7.7 на SQL-сервере. Каждому объекту метаданных (справочнику, документу, регистру), созданному в Конфигураторе, присваивается уникальный внутренний идентификатор (ID). Этот ID используется для именования физических таблиц в базе данных SQL, а также для адресации объектов внутри бинарного файла конфигурации 1Cv7.md.
Связующим звеном между конфигурацией 1Cv7.md и SQL-базой данных выступает файл словаря данных — 1Cv7.dds. В нем прописаны соответствия человекочитаемых имен объектов 1С именам таблиц в СУБД.
Например, документу "ПеременныеАОР" в системе может соответствовать внутренний числовой идентификатор 8132. В этом случае:
DH8132, а таблица табличной части — DT8132._1SJOURN в поле IDDOCDEF (идентификатор вида документа) для всех записей этого типа будет записываться значение, соответствующее этому ID в 36-ричной системе счисления.Суть проблемы ("подмена MD-файла"): Если в процессе разработки или обновления базы файл конфигурации 1Cv7.md был заменен некорректным образом (например, скопирован из копии базы, где этот же документ был удален и создан заново), его внутренний ID меняется. Допустим, в новом MD-файле документ "ПеременныеАОР" получил ID 8084. При этом физические таблицы в SQL-базе остались со старыми именами (DH8132), а в журнале _1SJOURN по-прежнему содержатся записи с IDDOCDEF, указывающим на несуществующий в новом MD-файле ID 8132.
Когда пользователь открывает журнал документов и начинает его прокручивать, платформа 1С отправляет SQL-запрос для выборки записей. Считывая очередную строку, движок платформы пытается сопоставить считанный из поля IDDOCDEF идентификатор 8132 со структурой метаданных в оперативной памяти, загруженной из нового файла 1Cv7.md. Не найдя объекта с таким ID, библиотека BkEnd.dll пытается обратиться по некорректному адресу памяти (разыменовывает нулевой указатель), что вызывает мгновенный сбой операционной системы с ошибкой Access Violation (0xC0000005) и закрытие программы у всех пользователей.
Проанализируем ситуацию и локализуем проблему с помощью прямых запросов к базе данных. Если в системе установлена внешняя компонента 1С++, мы можем выполнить тестовый запрос через консоль отчетов или обработку прямых запросов.
Рассмотрим пример запроса, который безотказно работает на корректной базе, но вызывает падение (или ошибку типизации) на проблемной:
SELECT Журнал.DATE_TIME_IDDOC ДатаВремяИдДок
, Журнал.IDDOC [Документ $Документ]
, Журнал.IDDOCDEF [Документ_вид $ВидДокументаПредставление]
, Журнал.DOCNO Документ_ном
FROM _1SJOURN AS Журнал With (NOLOCK)
ORDER BY Журнал.DATE_TIME_IDDOC
Если при попытке выполнить этот запрос с типизацией по метаданным $ВидДокументаПредставление внешняя компонента выдает ошибку вида:
Error # 5 : 0 : Invalid procedure call or argument
— это явный признак того, что парсер метаданных наткнулся на неизвестный ID вида документа в системной таблице журнала. Если же мы закомментируем строку с типизацией и выполним обычный SQL-запрос:
SELECT DATE_TIME_IDDOC, IDDOC, IDDOCDEF
FROM _1SJOURN (NOLOCK)
Запрос выполнится успешно. Внимательно проанализировав результат выборки, мы сможем увидеть конкретные значения в колонке IDDOCDEF. Сравнив их со списком идентификаторов документов, которые ожидает увидеть наш текущий MD-файл, мы легко вычислим "виновника". В нашем примере в СУБД физически существуют таблицы DH8132 и DT8132, в то время как в новом MD-файле документ "ПеременныеАОР" прописан под ID 8084, а таблиц DH8084 в базе SQL нет.
Первое решение, которое может прийти в голову системному администратору или SQL-разработчику, — это "подогнать" базу данных SQL под новый MD-файл прямо в СУБД. То есть переименовать таблицы DH8132 / DT8132 в DH8084 / DT8084 и выполнить SQL-запрос UPDATE для корректировки значений в колонке IDDOCDEF таблицы _1SJOURN.
Внимание! Делать этого категорически нельзя по следующим причинам:
RAxxxx), особенно если в конфигурации включена опция быстрой обработки движений или настроен отбор по измерениям._1SCRDOC. Вычистить их оттуда вручную и переписать под новые ID — колоссальный и рискованный труд.Поэтому самым надежным, быстрым и безопасным решением является приведение MD-файла конфигурации в соответствие с фактической структурой базы данных SQL.
Выяснив причину, мы восстановим исходный ID документа в конфигурационном файле 1Cv7.md, чтобы он снова ссылался на таблицы DH8132 / DT8132.
Для декомпиляции и сборки бинарного файла конфигурации мы воспользуемся проверенной утилитой gcomp. Посмотрим на процесс по шагам:
1Cv7.md и словаря данных 1Cv7.dds из каталога рабочей базы.Чтобы убедиться, какие именно объекты метаданных "разъехались", создайте на основе вашего текущего проблемного MD-файла новую пустую базу данных (можно в локальном DBF-формате). Запустите Конфигуратор новой базы и сохраните конфигурацию, чтобы система сгенерировала "чистый" файл 1Cv7.dd (или 1Cv7.dds). С помощью любой утилиты сравнения текстовых файлов (например, WinMerge) сравните DDS-файл рабочей SQL-базы и DDS-файл пустой базы. Вы увидите расхождения в именах таблиц для конкретных документов или справочников.
Поместим утилиту gcomp.exe и наш проблемный файл 1Cv7.md в одну папку (например, C:\GCompWork). Запустим командную строку и выполним распаковку конфигурации в текстовые файлы:
gcomp.exe -d -i 1Cv7.md -o UnpackedConf
После выполнения этой команды в каталоге UnpackedConf появится древовидная структура папок и текстовых файлов, полностью описывающих метаданные системы.
Перейдем в каталог с распакованными исходниками. Найдем файл описания нашего проблемного документа "ПеременныеАОР" (обычно файлы объектов лежат в подкаталогах метаданных и имеют расширение, соответствующее типу объекта). Откроем файл в текстовом редакторе (например, Notepad++). Найдем строку, в которой указан внутренний числовой ID документа (в нашем случае там будет прописано значение 8084). Заменим его на оригинальный ID из SQL-базы — 8132. Сохраним изменения.
С помощью утилиты gcomp соберем файлы исходников обратно в единый бинарный файл конфигурации. Выполним команду:
gcomp.exe -c -i UnpackedConf -o 1Cv7_fixed.md
Переименуем полученный файл 1Cv7_fixed.md в 1Cv7.md и скопируем его в каталог базы данных, предварительно убедившись, что все пользователи вышли из программы. Запустим Конфигуратор. Программа считает измененный файл, сопоставит его со словарем 1Cv7.dds и увидит, что документ "ПеременныеАОР" теперь снова ссылается на физически существующие таблицы DH8132 / DT8132.
После выполнения этих действий мы можем запустить 1С:Предприятие монопольно, открыть журнал документов и проверить скроллинг. Ошибка APPCRASH BkEnd.dll больше не побеспокоит пользователей, так как указатели в памяти платформы теперь ссылаются на корректно сопоставленные типы данных.
Для предотвращения подобных критических сбоев в будущем администраторам и разработчикам баз данных на платформе 1С 7.7 необходимо строго придерживаться следующих правил:
1Cv7.dds со словарем, генерируемым "чистой" конфигурацией. Любые расхождения — это потенциальные точки отказа системы.