При интеграции 1С с внешними базами данных через ADO (ActiveX Data Objects) программисты часто сталкиваются с проблемой передачи параметров в SQL-запрос. Начинающие разработчики нередко используют простую подстановку строк (конкатенацию), что приводит к ошибкам типизации и создает серьезные уязвимости, такие как SQL-инъекции. В этой статье мы подробно разберем, как правильно использовать объект ADODB.Command для безопасной и эффективной передачи параметров.
Рассмотрим ситуацию: вам нужно выбрать данные из SQL Server по определенному номеру документа. Самый очевидный, но неправильный путь — использование функции СтрЗаменить или сложение строк. Проанализируем риски:
1; DROP TABLE Users), что приведет к выполнению произвольного кода на сервере.Для правильной работы с параметрами нам потребуется объект ADODB.Command. Разберем по шагам процесс настройки соединения и подготовки запроса.
Сначала создадим объекты соединения и команды:
СоединениеSQL = Новый COMОбъект("ADODB.Connection");
КомандаSQL = Новый COMОбъект("ADODB.Command");
СоединениеSQL.ConnectionString = "Provider=MSOLEDBSQL;Data Source=ServerName;Initial Catalog=DBName;Integrated Security=SSPI;";
СоединениеSQL.Open();
КомандаSQL.ActiveConnection = СоединениеSQL;
Это универсальный способ, который поддерживается практически всеми провайдерами OLE DB. В тексте запроса вместо конкретных значений мы ставим знак вопроса. Посмотрим на пример:
ТекстЗапроса = "SELECT * FROM dbo.Orders WHERE OrderDate > ? AND TotalAmount > ?";
КомандаSQL.CommandText = ТекстЗапроса;
КомандаSQL.CommandType = 1; // adCmdText
Теперь нам нужно создать параметры и добавить их в коллекцию Parameters. Важно помнить, что при использовании знака вопроса параметры должны добавляться строго в том порядке, в котором они встречаются в тексте запроса.
Разберем метод CreateParameter. Он принимает следующие аргументы:
// Добавляем первый параметр (Дата)
ПараметрДата = КомандаSQL.CreateParameter("p_date", 135, 1, , ДатаНачала);
КомандаSQL.Parameters.Append(ПараметрДата);
// Добавляем второй параметр (Сумма)
ПараметрСумма = КомандаSQL.CreateParameter("p_amount", 3, 1, , 1000);
КомандаSQL.Parameters.Append(ПараметрСумма);
ВыборкаSQL = КомандаSQL.Execute();
Если вы работаете с Microsoft SQL Server, удобнее использовать именованные параметры. Это делает код более читаемым и позволяет не зависеть от порядка добавления параметров в коллекцию. Чтобы этот механизм заработал, необходимо установить свойство NamedParameters в значение Истина.
Рассмотрим пример реализации:
КомандаSQL.CommandText = "SELECT FIO FROM Personal WHERE TabNumber = @TabNum AND Status = @Status";
КомандаSQL.NamedParameters = Истина;
// Создаем и сразу добавляем параметры
КомандаSQL.Parameters.Append(КомандаSQL.CreateParameter("@TabNum", 3, 1, , 12345));
КомандаSQL.Parameters.Append(КомандаSQL.CreateParameter("@Status", 202, 1, 50, "Active"));
ВыборкаSQL = КомандаSQL.Execute();
Для корректной работы метода CreateParameter необходимо правильно указывать числовые коды типов (DataTypeEnum). Проанализируем наиболее часто используемые:
Важный нюанс при работе со строками: если вы используете типы adVarChar (200) или adVarWChar (202), обязательно указывайте четвертый параметр — размер строки. Если передать 0 или оставить пустым, ADO может обрезать строку до первого символа или выдать ошибку.
Выясним причину частых ошибок при передаче дат. В 1С "пустая" дата — это 01.01.0001. Однако SQL Server (тип datetime) поддерживает даты только начиная с 1753 года. Если попытаться передать пустую дату напрямую, запрос упадет с ошибкой.
Правильным подходом будет передача значения NULL, если дата не заполнена:
ЗначениеДляПередачи = ?(ДатаДокумента = '00010101', Null, ДатаДокумента);
Параметр = КомандаSQL.CreateParameter("@Date", 135, 1, , ЗначениеДляПередачи);
КомандаSQL.Parameters.Append(Параметр);
Если ваша логика вынесена на сторону SQL сервера в виде хранимой процедуры, работа с параметрами становится еще проще. Установим тип команды CommandType = 4 (adStoredProc):
КомандаSQL.CommandText = "sp_GetEmployeeData";
КомандаSQL.CommandType = 4;
// Имена параметров должны строго совпадать с именами в процедуре
КомандаSQL.Parameters.Append(КомандаSQL.CreateParameter("@EmployeeID", 3, 1, , 77));
ВыборкаSQL = КомандаSQL.Execute();
В этом режиме ADO понимает, что CommandText — это не SQL-запрос, а имя процедуры, и корректно сопоставляет коллекцию параметров с аргументами на сервере.
Для удобства работы в 1С мы рекомендуем создать вспомогательную функцию-обертку, которая будет автоматически определять тип параметра 1С и конвертировать его в код ADO. Это избавит вас от необходимости помнить числовые константы и сделает код чище.
Проанализируем основные выводы нашей работы:
ADODB.Command вместо прямого выполнения текста через Connection.Execute, если в запросе есть переменные.adVarWChar (202).NamedParameters = Истина для работы с именованными параметрами в MS SQL Server.Использование параметризованных запросов — это стандарт профессиональной разработки, обеспечивающий стабильность и безопасность ваших интеграционных решений между 1С и внешними СУБД. При необходимости организовать регулярный перенос информации без ручного написания запросов можно использовать подсистему выгрузки данных во внешнюю базу SQL.