Как запретить ADO изменять текст команды SQL?
Я бегу MERGE
заявление в отношении базы данных SQL Server 2008 R2 (которая находится в режиме совместимости 2008 года).
Точный оператор слияния SQL не имеет значения, но вот пример оператора MERGE:
MERGE Users
USING (VALUES
('{77410DC5-7A3E-4F1A-82C6-8EFB3068DE66}')
) AS rows(UserGUID)
ON Users.UserName = rows.UserName
WHEN NOT MATCHED BY SOURCE THEN
DELETE; --always end MERGE with semi-colon
При выполнении этого оператора из SSMS или с клиентского ПК под управлением Windows 7 он выполняется правильно.
Но когда мое программное обеспечение работает на клиентском компьютере под управлением Windows XP или Windows Server 2003 R2, sql CommandText
изменяется до достижения сервера. В SQL Server Profiler я вижу, что выполняется SQL:
exec MERGE Users
USING (VALUES
('{77410DC5-7A3E-4F1A-82C6-8EFB3068DE66}')
) AS rows(UserGUID)
ON Users.UserName = rows.UserName
WHEN NOT MATCHED BY SOURCE THEN
DELETE; --always end MERGE with semi-colon
Который не является допустимым SQL, и SQL Server выдает ошибку:
Incorrect syntax near the keyword 'MERGE'
Вы можете подтвердить, что это недопустимый SQL, попытавшись выполнить его в базе данных SQL Server 2008 R2.
Питер Боултон сообщил о той же проблеме на форумах Microsoft:
Синтаксис SQL MERGE работает с клиентом Win7 SP1, но не работает на более ранних платформах
Я считаю, что ADO анализирует SQL перед отправкой на сервер. Компоненты доступа к данным были обновлены для Win7 SP1, а также WinServer 2008 R2. Тем не менее, я считаю, что компоненты доступа к данным в XP SP3 предшествуют SQL Server 2008.
Вот почему SQL работает из Win7 SP1, но не из XP.
Моим "решением" было завернуть SQL в
EXEC
так что ADO позволяет это, как в:EXEC ('MERGE.... и т.д.)
Его взлом конечно работает, поменяй
MERGE Users ...
в
EXEC('MERGE Users' ...)
но я бы хотел найти реальное решение. Я не знаю, кто в цепочке отвечает за изменение текста моей команды:
ADO -> OLEDB -> SQLOLEDB -> SQL Server
но я хочу, чтобы они прекратили
Как мне через ADO указать текст моей команды, и чтобы SQLOLEDB не изменил его?
Прямо сейчас мой код 1:
String sqlCommandText = "MERGE Users" //snip;
int recordsAffected;
connection.Execute(
sqlCommandText,
out recordsAffected,
adCmdText | adExecuteNoRecords);
я не вижу ничего ExecuteOptionEnum
, или же CommandTypeEnum
сказать ADO и соответствующим провайдерам, чтобы текст воспринимался как необработанный.
На данный момент исправление взлома:
sql = "MERGE Users" ...
ExecuteNoRecords(connection, sql);
с измененным помощником:
int ExecuteNoRecords(Connection connection, String sql)
{
//20130611: Fix bug in ADO that mangles/breaks SQL it doesn't understand (e.g. MERGE on Windows XP)
String obfuscatedCommandText = 'EXEC(' + QuotedStr(sql)+ ')';
int recordsAffected;
connection.Execute(obfuscatedCommandText, out recordsAffected, adCmdText | adExecuteNoRecords);
return recordsAffected;
}
Обновление: лучший обходной путь
Вместо того, чтобы обернуть все утверждение в EXEC(...)
, я нашел более безопасный трюк, чтобы победить ADO, это предшествовать заявлению с комментарием. Даже пустой комментарий подойдет:
--
MERGE Users
USING (VALUES ...
В действительности вам понадобится текст, объясняющий, что пустая строка комментария имеет решающее значение для работы запроса:
--Leading comment to thwart ADO from mangling MERGE on Windows XP/2003R2
MERGE Users
USING (VALUES ...
1 ответ
Поскольку решения не существует, и ADO (хотя и не умерло) сделано, взломать ответ.
Никогда не выдавать MERGE
утверждение без ведущей строки комментария:
--Dummy leading comment line to thwart ADO from mangling MERGE on Windows XP/2003R2
MERGE Users
USING (VALUES ...