Как правильно экранировать MySQL запрос в 1С 7.7 при использовании ADODB

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

При интеграции 1С:Предприятия 7.7 с внешними базами данных MySQL через механизмы ADODB программисты часто сталкиваются с проблемой формирования корректных SQL-запросов. Основная сложность заключается в обработке строковых данных, содержащих спецсимволы, такие как одинарные кавычки в фамилиях (например, O'Reilly) или двойные кавычки в названиях организаций. Если не выполнить предварительное экранирование, SQL-сервер вернет синтаксическую ошибку, а в худшем случае система станет уязвимой для SQL-инъекций.

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

Почему стандартный подход с qStr не работает?

Разберем ситуацию, когда разработчик пытается использовать метод db.qStr(). Проблема заключается в том, что объект ADODB.Connection не содержит встроенного метода с таким именем. Это частое заблуждение, возникающее из-за смешивания синтаксиса различных библиотек или использования сторонних оберток над ADO, которые не входят в стандартную поставку Windows. При попытке вызова несуществующего метода 1С 7.7 закономерно выдает ошибку: "Аргументы имеют неверный тип, выходят за пределы допустимого диапазона или вступают в конфликт друг с другом".

Для решения задачи нам необходимо либо самостоятельно подготовить строку запроса, заменив в ней опасные символы, либо использовать специализированные объекты ADO для передачи параметров.

Реализация функции экранирования на базе VBScript.RegExp

Проанализируем наиболее эффективный способ ручной подготовки строки. Чтобы MySQL корректно воспринял одинарную кавычку внутри литерала, перед ней должен стоять обратный слэш (\). Для автоматизации этого процесса в 1С 7.7 удобно использовать объект VBScript.RegExp, который позволяет выполнять замену по шаблону.

Рассмотрим пример функции, которая ищет все вхождения одинарных кавычек и обратных слэшей, экранируя их:


Функция СтрMySQL(Вход)
    // Определяем константы для RegExp
    Истина = -1;
    Ложь = 0;
    
    // Создаем объект регулярных выражений
    RegExp = СоздатьОбъект("VBScript.RegExp");
    RegExp.IgnoreCase = Истина; // Игнорировать регистр
    RegExp.Global = Истина;     // Искать все вхождения
    RegExp.MultiLine = Истина;  // Многострочный режим
    
    // Шаблон ищет одиночную кавычку или обратный слэш
    // Важно экранировать сам слэш в шаблоне: (\\)
    RegExp.Pattern = "(')|(\\)"; 
    
    // Выполняем замену: добавляем обратный слэш перед найденным символом
    // Символ $& в RegExp означает "найденный текст"
    Возврат RegExp.Replace(Вход, "\$&");
КонецФункции

После обработки этой функцией строка Patrick O'Reilly превратится в Patrick O\'Reilly, что позволит безопасно вставить ее в SQL-запрос, обернув в одинарные кавычки.

Правила оформления строковых литералов в MySQL

Выясним причину, по которой простого удвоения кавычек (как в MS SQL или стандартном 1C) может быть недостаточно. MySQL по умолчанию использует обратный слэш как escape-символ. Рассмотрим по шагам, как правильно встраивать обработанную строку в тело запроса:

  1. Оборачивание в кавычки: Все строковые параметры должны быть заключены в одинарные кавычки ('). Хотя MySQL допускает использование двойных кавычек ("), использование одинарных является стандартом ANSI SQL.
  2. Обработка двойных кавычек: Если вы используете одинарные кавычки для обрамления строки, то двойные кавычки внутри самой строки экранировать необязательно, но желательно для универсальности.
  3. Специфические символы: Помимо кавычек, MySQL рекомендует экранировать символ NUL (ASCII 0), перенос строки (\n) и возврат каретки (\r).

Пример формирования итогового запроса:


ИмяКлиента = "Doctor ""Who"""; // Строка с двойными кавычками в 1С
БезопасноеИмя = СтрMySQL(ИмяКлиента);
SQL = "SELECT * FROM names WHERE name = '" + БезопасноеИмя + "'";
// Итог: SELECT * FROM names WHERE name = 'Doctor \"Who\"'

Использование параметризованных запросов через ADODB.Command

Рассмотрим более продвинутый и надежный метод, который рекомендуют системные администраторы и эксперты по безопасности. Вместо того чтобы вручную "склеивать" строку запроса, мы можем использовать объект ADODB.Command и коллекцию Parameters. Этот способ полностью снимает вопрос экранирования, так как драйвер ODBC берет эту задачу на себя.

Разберем пример реализации параметризованного запроса:


// Создаем соединение
db = СоздатьОбъект("ADODB.Connection");
db.Open("DSN=MyMySQL;UID=user;PWD=password;");

// Создаем команду
cmd = СоздатьОбъект("ADODB.Command");
cmd.ActiveConnection = db;
cmd.CommandText = "SELECT * FROM names WHERE name = ?";
cmd.CommandType = 1; // adCmdText

// Создаем и добавляем параметр
// 200 - adVarChar (тип данных)
// 1 - adParamInput (направление)
// 100 - размер поля
param = cmd.CreateParameter("pName", 200, 1, 100, "Patrick O'Reilly");
cmd.Parameters.Append(param);

// Выполняем запрос
rs = cmd.Execute();

Преимущество этого метода в том, что нам не нужно беспокоиться о наличии кавычек, слэшей или нулевых байтов в переменной. Объект ADODB.Command сам позаботится о правильной передаче данных серверу.

Важные нюансы: кодировки и системные настройки

Проанализируем ситуацию с кодировками, которая критична для 1С 7.7. Поскольку версия 7.7 работает в кодировке Windows-1251 (ANSI), при подключении к MySQL крайне важно явно указать это в строке соединения и настройках сессии. Если кодировка будет определена неверно, любые экранированные символы могут превратиться в "кракозябры", что разрушит синтаксис SQL-запроса.

Рекомендации по настройке соединения:

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

Подводя итог, можно выделить два основных пути решения проблемы:

  1. Быстрый путь: Использование функции на регулярных выражениях для замены ' на \' и \ на \\. Это отлично подходит для простых выборок и отчетов.
  2. Профессиональный путь: Использование ADODB.Command с параметрами. Это гарантирует 100% защиту от ошибок синтаксиса и взлома через SQL-инъекции, что особенно важно при записи данных в базу (INSERT/UPDATE).

Посмотрим на финальный пример надежной функции экранирования, учитывающей основные требования MySQL:


Функция EscapeMySQL(Значение)
    Результат = СтрЗаменить(Значение, "\", "\\");   // Сначала заменяем слэши
    Результат = СтрЗаменить(Результат, "'", "\'"); // Затем одинарные кавычки
    Результат = СтрЗаменить(Результат, """", "\"""); // Затем двойные кавычки
    Результат = СтрЗаменить(Результат, Симв(0), "\0"); // Нулевой символ
    Возврат Результат;
КонецФункции

Используя предложенные методы, вы сможете обеспечить стабильную работу обмена данными между 1С 7.7 и MySQL, исключив ошибки, связанные с именами, названиями и сложными текстовыми описаниями.

← На главную