Почему при прямых запросах к PostgreSQL поле _Code содержит нечитаемые символы и как это исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с прямыми запросами к базе данных PostgreSQL, на которой развернута платформа 1С:Предприятие, программисты часто сталкиваются с неприятной особенностью. При попытке получить данные из стандартных полей, таких как _Code (Код) или _Description (Наименование), через ADODB.Connection или стандартный драйвер ODBC, вместо привычных строк возвращается "каша" из нормальных символов и нечитаемых управляющих знаков (например, последовательности вида /x00/x08).

В этой статье мы подробно разберем, почему это происходит, как устроено хранение строк в "1С-ной" версии PostgreSQL и какие существуют способы решения этой проблемы — от простых правок в SQL-запросе до глобальных настроек на уровне базы данных.

Выясним причину: типы данных MCHAR и MVARCHAR

Разберем ситуацию: почему в PgAdmin данные видны корректно, в самой 1С — тоже, а при использовании ADODB в коде возникают ошибки? Причина кроется в глубокой модификации исходного кода PostgreSQL, которую вносит компания 1С (или которая присутствует в сборках Postgres Pro для 1С).

Для обеспечения совместимости логики работы со строками между MS SQL Server и PostgreSQL, платформа 1С использует специфические типы данных:

Эти типы данных реализуют специфическое сравнение строк (collations), обработку концевых пробелов и, что самое важное, используют библиотеку ICU для работы с кодировками. Внутри базы данных эти поля часто хранятся в формате, который стандартный ODBC-драйвер (например, PostgreSQL Unicode) не может интерпретировать однозначно. Для драйвера это "неизвестный тип" (Unknown type). Пытаясь прочитать его как обычный varchar, драйвер ошибочно считывает служебные заголовки или неверно определяет длину строки, что и приводит к появлению нечитаемых символов в конце значения.

Способ 1: Явное приведение типов (CAST)

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

Способ 2: Использование представлений (VIEW)

Рассмотрим ситуацию, когда запросов много, и в каждом писать 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";

Этот метод считается более профессиональным в архитектурном плане, так как он абстрагирует логику хранения данных от логики их получения.

Способ 3: Настройка неявного приведения типов (Implicit Cast)

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

Способ 4: Настройка строки подключения и драйвера

Разберем еще один нюанс, связанный с настройками самого соединения. Иногда проблема кроется не только в типах, но и в том, как драйвер интерпретирует "неизвестные" для него форматы. В строке подключения (ConnectionString) или в настройках DSN (Data Source Name) можно попробовать изменить поведение драйвера.

Посмотрим на параметры, которые могут помочь:

  1. STMT=utf8 — этот параметр в конце строки подключения принудительно устанавливает кодировку сообщений сервера.
  2. Unknowns as LongVarchar — в настройках драйвера PostgreSQL Unicode (вкладка Datasource, кнопка Page 2) установите эту галочку. Это заставит драйвер интерпретировать типы mchar как длинные строки, что часто избавляет от проблем с обрезкой или неверным чтением.

Пример расширенной строки подключения:

"Driver={PostgreSQL Unicode};Server=localhost;Port=5433;Database=mydb;Uid=user;Pwd=pass;STMT=utf8;"

Выводы и рекомендации

Подводя итог, можно сказать, что проблема нечитаемых символов — это не баг драйвера, а особенность реализации поддержки 1С в PostgreSQL. Для стабильной и предсказуемой работы мы рекомендуем следующее:

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

← На главную