Как исправить появление знаков вопроса вместо грузинских символов при передаче из 1С в MS SQL через внешние источники данных

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

При интеграции систем часто возникает ситуация, когда необходимо передавать строковые данные на различных национальных языках (например, грузинском, армянском или кириллице) из базы данных 1С в СУБД MS SQL. Однако разработчики, использующие механизм Внешних источников данных (ВИД) на старых версиях платформы (вплоть до 1С:Предприятие 8.3.12, включая популярную сборку 8.3.9.2170), сталкиваются с неприятным поведением: вместо красивых грузинских букв вроде საკისარი в базу данных MS SQL записываются исключительно знаки вопроса (?????).

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

Выясняем глубинную причину: почему NVARCHAR и префикс N не спасают?

Первое интуитивное действие любого SQL-разработчика при появлении знаков вопроса — проверить типы данных в приемнике и убедиться, что строковые литералы передаются с префиксом Юникода N. Однако в случае с Внешними источниками данных 1С классическая конструкция вида ProductName = "N'" + ProductName + "'" не приносит результата.

Проблема кроется в архитектуре взаимодействия платформы 1С с драйверами ODBC. При инициализации подключения к MS SQL платформа запрашивает метаданные СУБД, включая кодировку по умолчанию (Collation) всей базы данных. Если целевая база данных MS SQL имеет Collation семейства SQL_Latin1_General_* (что крайне часто встречается в зарубежных облачных инстансах, таких как Microsoft Azure, или при дефолтной установке английской версии SQL Server), ядро 1С делает ошибочный вывод:

«Внешняя база данных не поддерживает Unicode-символы в параметрах запросов».

В результате срабатывает внутренний алгоритм платформы 1С:

  1. Еще до отправки запроса драйверу ODBC ядро 1С принудительно конвертирует передаваемую строку в однобайтную кодовую страницу целевой СУБД (в данном случае CP1252 / Windows Western).
  2. Грузинские символы (диапазон Unicode U+10A0–U+10FF) физически отсутствуют в кодировке CP1252. В процессе необратимой конвертации они превращаются в байт 0x3F (символ знака вопроса ?).
  3. Драйвер ODBC получает от платформы 1С уже искаженную строку ????? и честно записывает ее в поле типа NVARCHAR. На стороне SQL-сервера мы видим знаки вопроса, хотя сам SQL-сервер настроен правильно.

Давайте разберем по шагам, как можно обойти эту проблему в рамках платформы 8.3.9.2170.

---

Решение 1. Изменение Collation на уровне базы данных MS SQL

Если у вас есть административный доступ к серверу MS SQL и изменение настроек базы данных не нарушит работу других связанных систем, это самый простой и чистый способ решить проблему раз и навсегда.

Платформа 1С перестанет принудительно урезать строки до CP1252, если изменить Collation базы данных на тот, который поддерживает кириллицу или национальные кодировки (например, Cyrillic_General_CI_AS или специализированный грузинский Georgian_Modern_Sort_CI_AS). При подключении к такой базе 1С поймет, что СУБД способна работать с расширенным набором символов.

Для изменения Collation выполните следующий T-SQL скрипт на стороне SQL-сервера (предварительно переведя базу в режим single user):


USE master;
ALTER DATABASE [ИмяВашейБазы] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
ALTER DATABASE [ИмяВашейБазы] COLLATE Cyrillic_General_CI_AS;
ALTER DATABASE [ИмяВашейБазы] SET MULTI_USER;

После изменения Collation пересоздайте подключение во Внешних источниках данных 1С. Строки начнут передаваться корректно без каких-либо изменений в программном коде.

---

Решение 2. Использование объектного способа работы с ВИДами

Если вы выполняете запись во внешнюю таблицу с помощью прямых SQL-запросов через конструкцию Новый Запрос (или динамические SQL-вызовы), платформа выполняет текстовую трансляцию запроса, где и происходит сбой кодировки.

Однако если использовать встроенные объектные методы работы с таблицами Внешних источников данных, платформа использует типизированные параметры. Рассмотрим пример объектной записи данных, который часто помогает избежать искажения кодировки:


// Получаем менеджер таблицы внешнего источника данных
НаборЗаписей = ВнешниеИсточникиДанных.ИмяВашегоИсточника.Таблицы.ИмяТаблицы.СоздатьНаборЗаписей();

// Создаем новую строку
НоваяСтрока = НаборЗаписей.Добавить();
НоваяСтрока.ProductName = "საკისარი"; // Грузинский текст "Подшипник"
НоваяСтрока.ProductCode = "SKF-102";

// Записываем данные в базу SQL
Попытка
    НаборЗаписей.Записать();
    Сообщить("Данные успешно записаны!");
Исключение
    Сообщить("Ошибка при записи: " + ОписаниеОшибки());
КонецПопытки;

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

---

Решение 3. Обходной путь через Base64-кодирование (Программный костыль)

Что делать, если база данных MS SQL вам не принадлежит (вы не можете менять Collation), а объектный способ записи по каким-то причинам недоступен или выдает ту же ошибку? В этом случае можно использовать красивый архитектурный обходной путь: передавать данные в кодировке Base64.

Суть метода заключается в том, что строка Base64 состоит исключительно из латинских букв и цифр (символы ASCII). Она гарантированно пройдет через любые ограничения конвертации 1С без искажений. На стороне MS SQL мы декодируем данные обратно в исходный Юникод.

Шаг 1. Кодирование строки на стороне 1С:

Напишем функцию для надежного преобразования строки в формат Base64 с явным указанием кодировки UTF-8:


Функция ПревратитьСтрокуВBase64(ИсходнаяСтрока) Экспорт
    // Создаем временный файл для записи текста в UTF-8
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("txt");
    
    ЗаписьТекста = Новый ЗаписьТекста(ИмяВременногоФайла, КодировкаТекста.UTF8);
    ЗаписьТекста.ЗаписатьСтроку(ИсходнаяСтрока);
    ЗаписьТекста.Закрыть();
    
    // Читаем файл как двоичные данные
    ДвоичныеДанные = Новый ДвоичныеДанные(ИмяВременногоФайла);
    СтрокаBase64 = ПолучитьBase64СтрокуИзДвоичныхДанных(ДвоичныеДанные);
    
    // Удаляем временный файл
    УдалитьФайлы(ИмяВременногоФайла);
    
    Возврат СтрокаBase64;
КонецФункции

Шаг 2. Декодирование на стороне MS SQL:

На стороне SQL-сервера мы можем восстановить исходную строку NVARCHAR, используя встроенный XML-декодер СУБД. Ниже представлен пример того, как это сделать в T-SQL:


-- Предположим, мы передали строку "საკისარი" в Base64: "4YOh4YOt4YOY4YOh4YOh4YOt4YOY"
DECLARE @Base64Encoded VARCHAR(MAX) = '4YOh4YOt4YOY4YOh4YOh4YOt4YOY';
DECLARE @DecodedText NVARCHAR(MAX);

-- Декодируем бинарные данные обратно в строку UTF-8
SET @DecodedText = CAST(
    CAST('' AS XML).value('xs:base64Binary(sql:variable("@Base64Encoded"))', 'VARBINARY(MAX)') 
    AS NVARCHAR(MAX)
);

SELECT @DecodedText; -- Вернет: საკისარი

Этот декодирующий функционал вы можете обернуть в SQL-триггер INSTEAD OF INSERT на целевой таблице или вызывать соответствующую хранимую процедуру. Этот способ полностью защищен от любых багов локализации платформы 1С.

---

Решение 4. Использование ADODB с типизированными параметрами (COM)

Автор обсуждения на форуме отметил, что при использовании ADODB через COM-соединение проблем с кодировкой не возникало. Однако COM-объекты могут работать медленнее при построчной обработке больших массивов данных. Чтобы решить проблему производительности при работе с COM, необходимо использовать параметризованные запросы.

Когда вы используете параметры в ADODB, вы явно указываете тип данных Юникод (тип 202 — adVarWChar). В этом случае драйвер OLE DB или ODBC передает данные напрямую в обход парсера строковых литералов 1С.

Проанализируем пример быстрой пакетной вставки данных с использованием параметров через ADODB:


Соединение = Новый COMОбъект("ADODB.Connection");
Команда = Новый COMОбъект("ADODB.Command");

// Строка подключения с использованием современного драйвера
СтрокаСоединения = "Provider=MSOLEDBSQL;Data Source=ИмяСервера;Initial Catalog=ИмяБазы;Integrated Security=SSPI;";
Соединение.Open(СтрокаСоединения);

Команда.ActiveConnection = Соединение;
Команда.CommandTimeout = 30;

// Подготавливаем параметризованный SQL-запрос
Команда.CommandText = "INSERT INTO Products (ProductCode, ProductName) VALUES (?, ?)";

// Создаем параметры (тип 202 соответствует adVarWChar для корректного Юникода)
ПараметрКод = Команда.CreateParameter("ProductCode", 202, 1, 50, "SKF-102");
Команда.Parameters.Append(ПараметрКод);

ПараметрИмя = Команда.CreateParameter("ProductName", 202, 1, 150, "საკისარი");
Команда.Parameters.Append(ПараметрИмя);

// Начинаем транзакцию для ускорения работы с большими объемами
Соединение.BeginTrans();

Попытка
    // Выполняем команду
    Команда.Execute();
    Соединение.CommitTrans();
    Сообщить("Строка успешно добавлена через ADODB!");
Исключение
    Соединение.RollbackTrans();
    Сообщить("Ошибка при записи: " + ОписаниеОшибки());
КонецПопытки;

Соединение.Close();

Применение явных транзакций (BeginTrans / CommitTrans) при работе через COM-соединение увеличивает скорость вставки данных в десятки раз, что практически нивелирует разницу в скорости с Внешними источниками данных.

---

Решение 5. Настройка строки подключения и параметров ODBC

В некоторых случаях искажение кодировки можно предотвратить тонкой настройкой параметров ODBC прямо в строке подключения Внешнего источника данных:

  1. Убедитесь, что на сервере 1С установлен современный драйвер СУБД. Вместо устаревшего драйвера {SQL Server} пропишите использование {ODBC Driver 17 for SQL Server} или {ODBC Driver 18 for SQL Server}.
  2. В параметрах строки подключения принудительно отключите автоматическую трансляцию OEM/ANSI символов локали операционной системы. Для этого добавьте в строку подключения параметр: AutoTranslate=No (или Translate=False).

Пример строки подключения для ВИД:

Driver={ODBC Driver 17 for SQL Server};Server=MyServer;Database=MyDatabase;Uid=myUsername;Pwd=myPassword;AutoTranslate=No;

Параметр AutoTranslate=No запрещает драйверу выполнять неявную конвертацию Юникод-символов в системную кодовую страницу Windows (которая на русскоязычных серверах по умолчанию является CP1251, а на англоязычных — CP1252), что позволяет сохранить исходные коды грузинских символов.

---

Резюме

Мы подробно разобрали системную проблему передачи не-латинских символов через Внешние источники данных в старых версиях 1С. Выяснили, что виновником является некорректная обработка кодовых страниц ядром платформы при взаимодействии со специфическими Collation баз данных MS SQL.

Для гарантированного решения проблемы рекомендуется:

← На главную