При работе с внешней компонентой 1sqlite в среде 1С:Предприятие 7.7 программисты иногда сталкиваются с крайне странным поведением: при выполнении SQL-запросов к данным DBF-базы числовые значения возвращаются без дробной части. Вместо ожидаемых 50.75 запрос возвращает 50, при этом типизация в запросе или использование арифметических операций не помогают. Рассмотрим детально, почему это происходит и как устранить проблему.
Проанализируем типичную ситуацию. Программист выполняет стандартный запрос к справочнику, где реквизит имеет тип Число с определенной точностью (например, 7.2). В таблицах DBF данные хранятся корректно, и стандартные средства 1С (списки, отчеты) видят дробную часть, но 1sqlite упорно ее "отрезает".
Рассмотрим пример кода, который вызывает проблему:
SELECT
СпрАбоненты.[ID] AS [СпрАбоненты_Ссылка :Справочник.Абоненты],
СпрАбоненты.[ОбщаяПлощадь] AS [СпрАбоненты_ОбщаяПлощадь :Число.7.2]
FROM
[Справочник.Абоненты] AS СпрАбоненты
Даже если мы попытаемся принудительно умножить значение на число с плавающей точкой, результат часто остается целочисленным или округленным некорректно. Например, операция 1.1 * Площадь при значении 50.7 может вернуть 55 (отбросив 0.7 перед умножением) или другие непредсказуемые результаты.
Прежде чем переходить к радикальным мерам, проверим, как система видит реквизит на уровне метаданных. Мы можем использовать встроенный язык 1С для проверки характеристик поля:
Реквизит = Метаданные.Справочник("Абоненты").Реквизит("ОбщаяПлощадь");
Сообщить("Тип " + Реквизит.Тип + " Длина " + Реквизит.Длина + " Точность " + Реквизит.Точность);
Если метаданные возвращают верные значения (например, точность 2), а 1sqlite все равно выдает целые числа, значит, проблема кроется не в описании структуры данных, а в механизме их извлечения и преобразования типов внутри самой компоненты или в ее окружении.
Разберем ситуацию глубже. Внешняя компонента 1sqlite написана на C++ и использует стандартные механизмы SQLite для работы с данными. При обращении к DBF-файлам (которые по сути являются текстовыми хранилищами для чисел типа N), компонента должна преобразовать строку в число с плавающей запятой (типа double в C++ или REAL в SQLite).
Проанализируем влияние других загруженных библиотек. Одной из часто используемых компонент в 1С 7.7 является v7lua.dll, которая применяется для раскраски текста в полях ввода и расширения функционала скриптами Lua. Именно здесь кроется корень зла.
Многие библиотеки, написанные на Delphi или использующие специфические среды исполнения (как Lua), при загрузке меняют состояние FPU Control Word (управляющего слова процессора). Это меняет режим работы сопроцессора с плавающей точкой:
Кроме того, некоторые компоненты могут неявно вызывать функцию setlocale, меняя разделитель дробной части с точки на запятую. Поскольку SQLite ожидает точку в качестве разделителя при парсинге строк из DBF, он просто перестает видеть дробную часть, останавливая чтение числа на разделителе.
Посмотрим на практические способы решения этой проблемы, если вы обнаружили, что дробная часть пропадает именно при совместном использовании 1sqlite и дополнительных интерфейсных библиотек.
Выясним, действительно ли виновата v7lua.dll. Попробуйте временно исключить ее загрузку из процедуры ПриНачалеРаботыСистемы(). Если после этого запросы 1sqlite начинают возвращать дробную часть корректно — причина найдена. Поскольку эта библиотека часто используется только для визуальных эффектов (раскраска кода в текстовых редакторах), ее можно заменить на более стабильные аналоги.
Если вам необходима раскраска синтаксиса или продвинутые поля ввода (Scintilla), рекомендуется использовать sci.dll напрямую, без посредничества Lua-скриптов. Современные реализации классов для 1cpp.dll позволяют управлять функционалом Scintilla на чистом языке 1С. Это исключает влияние среды исполнения Lua на математический сопроцессор.
Иногда (хотя и не всегда) помогает изменение последовательности инициализации библиотек. Попробуйте загрузить 1sqlite.dll самой первой, до загрузки любых других ВК (v7plus.dll, FormEx.dll, v7lua.dll). В некоторых случаях это позволяет 1sqlite инициализировать свои обработчики типов до того, как другие библиотеки внесут изменения в глобальное состояние процесса.
Важно отметить интересную особенность, выявленную при анализе работы 1sqlite. Периодические реквизиты (которые хранятся в таблице 1s_const) часто отображаются корректно даже при наличии конфликтов. Это происходит потому, что в 1s_const значения хранятся в строковом поле VALUE, и логика их извлечения может отличаться от чтения напрямую из физических колонок DBF-таблиц справочников.
Рассмотрим пример корректного получения цены (периодического значения):
SELECT
СпрНоменклатура.[ID] AS [Ссылка],
(SELECT Value
FROM Константы
WHERE (OBJID = СпрНоменклатура.ID)
AND (ID = :ИсторияРеквизита.Номенклатура.Цена)
AND (Date <= '20220101')
ORDER BY Date DESC
LIMIT 1) AS [Цена :Число.15.2]
FROM
[Справочник.Номенклатура] AS СпрНоменклатура
Если такой запрос работает, а запрос к обычному реквизиту — нет, это окончательно подтверждает проблему парсинга числовых полей в виртуальных таблицах 1sqlite из-за сбитых настроек окружения.
Подводя итог, проанализируем последовательность действий для исправления ошибки:
v7lua.dll.sqlite (обычно версия самой библиотеки sqlite3.dll не влияет на этот баг, так как он находится на стыке интерфейса ВК и операционной системы).1cpp.dll + sci.dll, избегая лишних надстроек.v7lua, которые корректно восстанавливают состояние процессора после выполнения своих функций.Помните, что среда 1С 7.7 является 32-битным процессом, где все загруженные DLL делят общее адресное пространство и общие системные ресурсы, включая настройки математического сопроцессора. Внимательное отношение к списку используемых ВК — залог стабильной работы сложных аналитических запросов.