Почему 1sqlite в 1С 7.7 отбрасывает дробную часть чисел и как это исправить

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При работе с внешней компонентой 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 все равно выдает целые числа, значит, проблема кроется не в описании структуры данных, а в механизме их извлечения и преобразования типов внутри самой компоненты или в ее окружении.

Выяснение технической причины: конфликт FPU и локали

Разберем ситуацию глубже. Внешняя компонента 1sqlite написана на C++ и использует стандартные механизмы SQLite для работы с данными. При обращении к DBF-файлам (которые по сути являются текстовыми хранилищами для чисел типа N), компонента должна преобразовать строку в число с плавающей запятой (типа double в C++ или REAL в SQLite).

Проанализируем влияние других загруженных библиотек. Одной из часто используемых компонент в 1С 7.7 является v7lua.dll, которая применяется для раскраски текста в полях ввода и расширения функционала скриптами Lua. Именно здесь кроется корень зла.

Многие библиотеки, написанные на Delphi или использующие специфические среды исполнения (как Lua), при загрузке меняют состояние FPU Control Word (управляющего слова процессора). Это меняет режим работы сопроцессора с плавающей точкой:

  1. Меняется точность вычислений.
  2. Изменяются правила округления.
  3. Перехватываются исключения (например, деление на ноль).

Кроме того, некоторые компоненты могут неявно вызывать функцию setlocale, меняя разделитель дробной части с точки на запятую. Поскольку SQLite ожидает точку в качестве разделителя при парсинге строк из DBF, он просто перестает видеть дробную часть, останавливая чтение числа на разделителе.

Решение проблемы: устранение конфликта библиотек

Посмотрим на практические способы решения этой проблемы, если вы обнаружили, что дробная часть пропадает именно при совместном использовании 1sqlite и дополнительных интерфейсных библиотек.

Способ 1. Отказ от использования v7lua.dll

Выясним, действительно ли виновата v7lua.dll. Попробуйте временно исключить ее загрузку из процедуры ПриНачалеРаботыСистемы(). Если после этого запросы 1sqlite начинают возвращать дробную часть корректно — причина найдена. Поскольку эта библиотека часто используется только для визуальных эффектов (раскраска кода в текстовых редакторах), ее можно заменить на более стабильные аналоги.

Способ 2. Переход на прямую работу с sci.dll

Если вам необходима раскраска синтаксиса или продвинутые поля ввода (Scintilla), рекомендуется использовать sci.dll напрямую, без посредничества Lua-скриптов. Современные реализации классов для 1cpp.dll позволяют управлять функционалом Scintilla на чистом языке 1С. Это исключает влияние среды исполнения Lua на математический сопроцессор.

Способ 3. Изменение порядка загрузки компонент

Иногда (хотя и не всегда) помогает изменение последовательности инициализации библиотек. Попробуйте загрузить 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 из-за сбитых настроек окружения.

Итоги и рекомендации

Подводя итог, проанализируем последовательность действий для исправления ошибки:

  1. Проверьте, не загружена ли у вас компонента v7lua.dll.
  2. Убедитесь, что проблема сохраняется на разных версиях sqlite (обычно версия самой библиотеки sqlite3.dll не влияет на этот баг, так как он находится на стыке интерфейса ВК и операционной системы).
  3. Для реализации интерфейсных задач (раскраска кода, редакторы) используйте проверенные связки, такие как 1cpp.dll + sci.dll, избегая лишних надстроек.
  4. Если отказ от библиотеки невозможен, попробуйте использовать специализированные сборки v7lua, которые корректно восстанавливают состояние процессора после выполнения своих функций.

Помните, что среда 1С 7.7 является 32-битным процессом, где все загруженные DLL делят общее адресное пространство и общие системные ресурсы, включая настройки математического сопроцессора. Внимательное отношение к списку используемых ВК — залог стабильной работы сложных аналитических запросов.

← На главную