При работе с прямыми запросами к базе данных PostgreSQL, на которой развернута платформа 1С:Предприятие, программисты часто сталкиваются с неприятной особенностью. При попытке получить данные из стандартных полей, таких как _Code (Код) или _Description (Наименование), через ADODB.Connection или стандартный драйвер ODBC, вместо привычных строк возвращается "каша" из нормальных символов и нечитаемых управляющих знаков (например, последовательности вида /x00/x08).
В этой статье мы подробно разберем, почему это происходит, как устроено хранение строк в "1С-ной" версии PostgreSQL и какие существуют способы решения этой проблемы — от простых правок в SQL-запросе до глобальных настроек на уровне базы данных.
Разберем ситуацию: почему в PgAdmin данные видны корректно, в самой 1С — тоже, а при использовании ADODB в коде возникают ошибки? Причина кроется в глубокой модификации исходного кода PostgreSQL, которую вносит компания 1С (или которая присутствует в сборках Postgres Pro для 1С).
Для обеспечения совместимости логики работы со строками между MS SQL Server и PostgreSQL, платформа 1С использует специфические типы данных:
mchar — аналог nchar (строка фиксированной длины).mvarchar — аналог nvarchar (строка переменной длины).Эти типы данных реализуют специфическое сравнение строк (collations), обработку концевых пробелов и, что самое важное, используют библиотеку ICU для работы с кодировками. Внутри базы данных эти поля часто хранятся в формате, который стандартный ODBC-драйвер (например, PostgreSQL Unicode) не может интерпретировать однозначно. Для драйвера это "неизвестный тип" (Unknown type). Пытаясь прочитать его как обычный varchar, драйвер ошибочно считывает служебные заголовки или неверно определяет длину строки, что и приводит к появлению нечитаемых символов в конце значения.
Проанализируем самый быстрый и надежный способ решения "в лоб". Если нам нужно получить корректные данные в конкретном запросе, мы должны явно указать серверу PostgreSQL, что данные нужно преобразовать в стандартный текстовый тип, понятный любому клиенту.
Вместо использования небезопасного SELECT *, мы перечисляем нужные поля и применяем функцию CAST. Рассмотрим пример кода:
// Вместо: SELECT _Code, _Description FROM _Reference31
// Используем явное приведение:
ЗапросSQL = "SELECT
CAST(_Code AS varchar) as Code,
CAST(_Description AS varchar) as Description
FROM _Reference31";
Почему это работает: функция CAST заставляет сервер выполнить внутреннюю конвертацию из "магического" типа 1С в стандартный varchar. В этот момент сервер отсекает лишние служебные символы и передает клиенту чистую строку в кодировке UTF-8 (или той, что указана в настройках соединения).
Рассмотрим ситуацию, когда запросов много, и в каждом писать CAST неудобно, или когда вам принципиально важно использовать конструкцию SELECT *. В этом случае мы можем переложить задачу по трансформации типов на сторону сервера базы данных, создав "обертку".
Выполним в консоли запросов PostgreSQL (например, через PgAdmin) следующий скрипт:
CREATE OR REPLACE VIEW v_reference31 AS
SELECT
_idrref,
_marked,
CAST(_code AS varchar) as _code,
CAST(_description AS varchar) as _description
FROM _reference31;
Теперь в коде 1С вы можете обращаться к этой VIEW точно так же, как к таблице, и получать чистые данные без лишних усилий:
ЗапросSQL = "SELECT * FROM v_reference31";
Этот метод считается более профессиональным в архитектурном плане, так как он абстрагирует логику хранения данных от логики их получения.
Проанализируем более продвинутый системный метод. Если вы не хотите создавать представления для каждой таблицы, можно "научить" PostgreSQL автоматически преобразовывать типы mchar и mvarchar в стандартный varchar при передаче данных клиенту. Это делается через создание системных правил приведения типов.
Внимание: данные действия требуют прав суперпользователя базы данных и должны быть предварительно протестированы на копии базы!
-- Разрешаем автоматическое приведение mchar к varchar
CREATE CAST (mchar AS varchar) WITH INOUT AS IMPLICIT;
-- Разрешаем автоматическое приведение mvarchar к varchar
CREATE CAST (mvarchar AS varchar) WITH INOUT AS IMPLICIT;
После выполнения этих команд стандартный драйвер ODBC начнет получать данные в понятном ему формате даже при выполнении SELECT *. Однако помните, что при обновлении платформы 1С или версии PostgreSQL эти настройки могут быть сброшены или привести к конфликтам с новыми патчами от разработчиков платформы.
Разберем еще один нюанс, связанный с настройками самого соединения. Иногда проблема кроется не только в типах, но и в том, как драйвер интерпретирует "неизвестные" для него форматы. В строке подключения (ConnectionString) или в настройках DSN (Data Source Name) можно попробовать изменить поведение драйвера.
Посмотрим на параметры, которые могут помочь:
mchar как длинные строки, что часто избавляет от проблем с обрезкой или неверным чтением.Пример расширенной строки подключения:
"Driver={PostgreSQL Unicode};Server=localhost;Port=5433;Database=mydb;Uid=user;Pwd=pass;STMT=utf8;"
Подводя итог, можно сказать, что проблема нечитаемых символов — это не баг драйвера, а особенность реализации поддержки 1С в PostgreSQL. Для стабильной и предсказуемой работы мы рекомендуем следующее:
CAST(поле AS varchar). Это защитит вас от изменений структуры таблиц и проблем с типами.PostgreSQL Unicode Driver (x64 для 64-битных систем), так как в старых версиях драйверов работа с Unicode-типами реализована менее стабильно.Помните, что прямой доступ к таблицам 1С — это мощный инструмент, требующий понимания внутренней структуры данных платформы. Соблюдение этих простых правил позволит вам избежать проблем с кодировками и обеспечит корректную передачу данных в ваши внешние системы.