При работе с внешней компонентой 1sqlite в среде 1С:Предприятие 7.7 разработчики часто сталкиваются с необходимостью расширения стандартных возможностей движка SQLite. Одним из самых популярных расширений является sqlite3_mod_csv, позволяющее подключать текстовые файлы как виртуальные таблицы. Однако при вызове функции load_extension может возникнуть ошибка "not authorized". Эта ошибка особенно коварна тем, что она может проявляться не постоянно, а «выскакивать» в процессе работы сеанса, который запущен длительное время (например, у робота-обработчика).
В этой статье мы подробно разберем причины возникновения этой проблемы, проанализируем механизмы безопасности SQLite и предложим комплексное решение для стабильной работы ваших баз данных.
Для начала проанализируем природу ошибки. Важно понимать, что not authorized (код ошибки SQLITE_AUTH) — это не проблема доступа к файлу на уровне операционной системы и не блокировка базы другим пользователем (в этом случае SQLite вернула бы database is locked). Эта ошибка генерируется внутренним механизмом безопасности самого движка SQLite.
По умолчанию в SQLite возможность загрузки внешних динамических библиотек (расширений) отключена. Это сделано для предотвращения несанкционированного выполнения произвольного кода через SQL-инъекции. Чтобы функция load_extension заработала, необходимо явно вызвать программный метод, который установит соответствующий флаг в текущем соединении. Если этот флаг по какой-то причине сбрасывается или не устанавливается при переподключении, мы получаем ошибку авторизации.
Самый важный шаг в решении проблемы — использование специализированного метода компоненты 1sqlite. Рассмотрим, как правильно модифицировать код инициализации запроса. Проанализируем ситуацию: если ваш объект База (созданный через СоздатьОбъект("sqlite")) пересоздается или внутреннее соединение сбрасывается, флаг разрешения загрузки расширений обнуляется.
Разберем пример кода, который гарантированно включает нужные права перед загрузкой модуля:
// Создаем объект базы, если он еще не создан
База = СоздатьОбъект("sqlite");
База.Открыть(":memory:"); // Или путь к файлу базы
// КРИТИЧЕСКИ ВАЖНАЯ СТРОКА:
// Разрешаем загрузку внешних расширений для текущего соединения
База.РазрешитьЗагрузкуРасширений(1);
Запрос = База.НовыйЗапрос();
// Теперь попытка загрузки не вызовет ошибку авторизации
Запрос.ВыполнитьЗапрос("SELECT load_extension('sqlite3_mod_csv','sqlite3_extension_init');");
Важный совет: Если код выполняется в цикле или внутри сеанса робота, который работает 24/7, вызывайте База.РазрешитьЗагрузкуРасширений(1) непосредственно перед каждым блоком кода, где используется load_extension. Это подстрахует вас на случай неявного переподключения компоненты к ядру БД.
Иногда ошибка может быть косвенно вызвана тем, что движок SQLite не может найти файл расширения, и из-за особенностей обработки путей в 1С 7.7 это интерпретируется неверно. Рассмотрим, как жестко задать контекст поиска библиотеки, если она лежит в каталоге информационной базы.
Посмотрим на алгоритм временной смены каталога:
ТекущийКаталог = ФС.ТекКаталог();
// Устанавливаем путь к папке, где лежит sqlite3_mod_csv.dll
ФС.УстТекКаталог(КаталогИБ());
Попытка
База.РазрешитьЗагрузкуРасширений(1);
Запрос.ВыполнитьЗапрос("SELECT load_extension('sqlite3_mod_csv');");
Исключение
Сообщить("Ошибка загрузки расширения: " + ОписаниеОшибки());
КонецПопытки;
// Возвращаем каталог на место, чтобы не нарушить работу других модулей 1С
ФС.УстТекКаталог(ТекущийКаталог);
Если ошибка возникает в моменты, когда с базой работают одновременно несколько пользователей, следует пересмотреть параметры производительности и журналирования. Хотя автор темы упоминал PRAGMA synchronous = OFF и journal_mode = MEMORY, для стабильности в многопользовательском режиме (особенно для роботов) рекомендуется использовать режим WAL (Write-Ahead Logging).
Проанализируем рекомендуемые настройки:
Рассмотрим пример правильной настройки сессии:
Запрос = База.НовыйЗапрос();
// Устанавливаем режим WAL для стабильной многопользовательской работы
Запрос.ВыполнитьЗапрос("PRAGMA journal_mode = WAL;");
// Устанавливаем время ожидания блокировки в 5000 миллисекунд (5 секунд)
Запрос.ВыполнитьЗапрос("PRAGMA busy_timeout = 5000;");
// Теперь выполняем загрузку расширения
База.РазрешитьЗагрузкуРасширений(1);
Запрос.ВыполнитьЗапрос("SELECT load_extension('sqlite3_mod_csv');");
Если вы разрабатываете робота на базе 1С 7.7, который должен работать бесперебойно, прислушайтесь к следующим рекомендациям по работе с 1sqlite:
load_extension в рамках одного и того же соединения может привести к нестабильности или падению приложения. Проверить, загружен ли модуль, можно через PRAGMA module_list.journal_mode = MEMORY существует риск переполнения оперативной памяти при очень больших объемах транзакций. Режим WAL более безопасен, так как пишет изменения в файл -wal на диске.Попытка...Исключение. Если получена ошибка "not authorized", программно уничтожайте объект База (приравнивая его к 0), делайте паузу ВвестиСтроку или Sleep и инициализируйте соединение заново с вызовом РазрешитьЗагрузкуРасширений(1).Таким образом, мы выяснили, что корень проблемы лежит в плоскости безопасности SQLite. Использование метода РазрешитьЗагрузкуРасширений(1) в сочетании с переходом на WAL режим обеспечит надежную работу ваших решений на платформе 1С 7.7.