Предыстория
Как-то обратились ко мне с этой ошибкой в одной базе УНФ. Не проходило обновление на версию 3.0.9 - при выполнении обработчиков обновления база останавливалась. Тестирование и исправление падало на реструктуризации с этой же ошибкой.
Конфигурация типовая, но с обширными доработками, вынесенными в расширение.
Выяснилось, что ошибка возникла уже в версии 3.0.8, только там обработчики выполнились нормально, но в работе ошибка возникала, и Тестирование тоже не проходило. Возврат к копии до обновления на 3.0.8 можно было рассматривать только в крайнем случае - в базе уже успели поработать.
Удачно, что база была серверная, в PostgreSQL, так удобнее работать непосредственно с базой
ВНИМАНИЕ! 1С не одобряет работу с базами 1С напрямую без использования платформы. Не следует обращаться к данным базы напрямую в рабочем режиме.
Расследование
Беглый поиск по интернету показал что ошибка не уникальная, связана с расширениями, в которых определен свой план обмена. Но в качестве решений предлагается удалять расширение и заново подключать, а данные попробовать выгрузить в файл и потом загрузить обратно. С тем что данные расширения надо было сохранить, решение я запомнил, но оценил как экстремальное, не гарантирующее результат как по времени так и по собственно результату.
Выяснилось, что произошла накладка со структурой базы данных. Ошибки SDBL - ошибки структуры базы. Планы обмена хранятся в таблицах _Node*, и начиная с уровня совместимости платформы 8.3.22 в эти таблицы добавляется служебное поле LastUpdate.
УНФ версии 3.0.7 использует уровень совместимости платформы 8.3.21, а 3.0.8 - уже 8.3.24.
Проблема была в том что в базе было большое расширение со своим планом обмена, и в его таблицу это поле не было добавлено. Не могу сказать что привело к такой проблеме - на тестовой пустой базе мне не удалось проблему воспроизвести.
Изменение уровня совместимости расширения ничего не давало. Удалить только план обмена из расширения не получилось, не прошла реструктуризация, были ссылки на настроенный план обмена. Скорее всего получилось бы сначала из режима предприятия удалить настройку синхронизации и только после этого удалять сам план, но это тоже было бы экстремальным решением, которого хотелось избежать.
Немного о внутренностях баз 1С
ВНИМАНИЕ! 1С не одобряет работу с базами 1С напрямую без использования платформы. Не следует обращаться к данным базы напрямую в рабочем режиме.
В данном случае придётся залезть в недра базы с целью исправления ошибки, исправление другими способами невозможно или проблематично. Манипуляции проводятся на свой страх и риск, обязательно нужно сделать копию базы.
В базе информация о настройках синхронизации хранится в таблицах планов обмена с именами _Node*
Используются служебные поля
_IDRREF - Уникальный идентификатор узла обмена
_Version - служебное поле
_Marked - пометка удаления
_Code - код узла
_Description - наименование узла
_SentNo - номер отправленного сообщения
_receivedno - номер принятого сообщения
_predefinedid - идентификатор предопределенного узла
_LastUpdate - видимо дата последнего изменения узла, добавлено в платформе 8.3.22
_fld* - пользовательские поля плана обмена
Таблицы планов обмена, объявленные или измененные в расширениях, именуются с суффиксом X1, например _Node55X1. Соответствие конкретных номеров таблиц и полей метаданным дерева конфигуратора описывается в таблице Params в записях с именами вида DBNames*. Для конфигурации это "DBNames", для расширений - "DBNames-Ext-*"
Также в базе хранится описание физической структуры базы, т.е. имена таблиц, полей с типами и ограничениями, индексов. В таблице DBSchema хранится описание структуры основной конфигурации, в SCHEMASTORAGE с SchemaID=0 хранится описание структуры основной конфигурации (повторяет данные из DBSchema), c другими SchemaID - структура объектов, добавленных расширениями.
Посмотреть эти данные можно для файловых баз с помощью Tool_1CD, для серверных - с помощью средств администрирования СУБД, например PGAdmin для PostgreSQL
Описание структуры базы хранится в сериализованном виде, в виде списков вида
{"Node47566","N",47566,"",
{13,
{"ID",0,
{1,
{"R",0,0,"Node47566",2}
},"",0},
{"Version",0,
{1,
{"V",0,0,"",0}
},"",0},
Исправление ошибки
Внимание! Все манипуляции в базе с изменениями стоит делать при остановленном сервере 1С. В крайнем случае - заблокировать начало сеансов и регламентные, удалить все сеансы. После изменений если сервер 1С не останавливали желательно базу передобавить или изменить параметры базы или сервера на левые и потом вернуть обратно. Делается это чтобы в сервере 1С не осталось закешированных неактуальных данных.
Первое и очевидное - добавить недостающее поле. В PostgreSQL это можно сделать запросом:
ALTER TABLE public._node47566x1 ADD COLUMN _lastupdate timestamp without time zone NOT NULL DEFAULT now()
Тут _node47566x1 - это имя той самой проблемной таблицы. Выяснить его можно или просматривая все таблицы базы вида _nodeNNNx1, или по имени предварительно получив структуру базы в 1С функцией ПолучитьСтруктуруХраненияБазыДанных() или любой из многочисленных обработок.
Для MSSQL запрос будет в целом похож, немного доработать напильником, для файловых баз по возможности я бы посоветовал перенести временно базу в PostgreSQL, либо можно поработать Tool_1CD плюс доработать данные напильником.
Как оказалось, просто добавить столбец в базу было недостаточно. Платформа сначала смотрит в описание структуры, а в описании этого поля нет.
Выгружаю данные в файл. Мне было удобно это сделать небольшим PHP-скриптом вида:
<?php
$db=pg_connect('host=127.0.0.1 user=postgres dbname=onec_tmp_p password=****');
pg_query('set bytea_output to hex');
$pgr=pg_query('SELECT CURRENTSCHEMA FROM SCHEMASTORAGE WHERE SCHEMAID=1');
$r=pg_fetch_array($pgr);
file_put_contents('schemastorage.hex',hex2bin(substr($r[0],2)));
?>
Как альтернатива - выгрузить таблицу через pg_dump в файл и нужное значение преобразовать из HEX.
pg_dump.exe -h 127.0.0.1 -U postgres -t schemastorage onec_tmp_p >schemastorage.txt
В получившемся файле в текстовом редакторе нахожу описание нужной таблицы, начинается примерно так:
{"Node47566","N",47566,"",
{13,
{"ID",0,
{1,
{"R",0,0,"Node47566",2}
},"",0},
{"Version",0,
{1,
{"V",0,0,"",0}
Во второй строке число 13 - количество полей в описании. Проверяю что поля LastUpdate нет и его надо добавить. Редактирую: изменяю 13 на 14 (в вашем случае число может быть другим, просто увеличиваю на единицу), и вставляю описание нового поля, в конец списка или перед описанием любого другого поля (для серверных баз):
{"LastUpdate",0,
{1,
{"T",0,0,"",0}
},"",0},
Получившийся файл надо загрузить обратно в базу, я это делал опять же с помощью PHP:
<?php
$db=pg_connect('host=127.0.0.1 user=postgres dbname=onec_tmp_p password=****');
pg_query('set bytea_output to hex');
$st='\\x'.bin2hex(file_get_contents('schemastorage.txt'));
pg_query_params('UPDATE schemastorage SET currentschema=$1 WHERE schemaid=1',[$st]);
?>
Запускаю базу - УРА! Тестирование и исправление с реструктуризацией проходит (реструктуризацию надо сделать обязательно, чтобы 1С подчистила за нами все неаккуратности), база работает, последующее обновление проходит успешно.
Остаётся только пожелать не сталкиваться с такими ошибками и всегда иметь актуальные бекапы.
Вступайте в нашу телеграмм-группу Инфостарт