Как запретить 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 ...
Другие вопросы по тегам