Я запускаю инструкцию MERGE
к базе данных SQL Server 2008 R2 (которая находится в режиме совместимости 2008 года).Как предотвратить изменение ADO моего текста команды SQL?
Точное слияния оператор 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 syntax works with Win7 SP1 client but fails with earlier platforms
I believe ADO parses the SQL before it sends it to the server. The data access components were updated for Win7 SP1 and also WinServer 2008 R2. However, I believe XP SP3's data access components predate SQL Server 2008.
That's why the SQL works from Win7 SP1 but not from XP.
My 'solution' was to wrap the SQL in an
EXEC
so that ADO allows it through, as in:EXEC('MERGE....etc.')
Его хак, конечно, работает, изменение:
MERGE Users ...
в
EXEC('MERGE Users' ...)
, но я хотел бы придумать реальное решение. Я не знаю, кто в цепочке несет ответственность за изменение текста моей команды:
ADO -> OLEDB -> SQLOLEDB -> SQL Server
но я хочу, чтобы они остановились.
Как я, через ADO, указать свой текст команды и SQLOLEDB не изменить его?
Сейчас мой код :
String sqlCommandText = "MERGE Users" //snip;
int recordsAffected;
connection.Execute(
sqlCommandText,
out recordsAffected,
adCmdText | adExecuteNoRecords);
я не вижу ExecuteOptionEnum
или CommandTypeEnum
сказать ADO, и лежащие в основе поставщиков, чтобы рассматривать текст, как сырой.
В настоящее время Fixup хак:
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;
}
Update: Лучше обходной путь взломать
Вместо того, чтобы упаковка целиком заявление в EXEC(...)
, я нашел более безопасный трюк, чтобы победить ADO, чтобы предшествовать заявлению с помощью комментарий.Даже пустой комментарий будет делать:
--
MERGE Users
USING (VALUES ...
В действительности вы будете хотеть иметь некоторый текст, объясняющий, что комментарий пустая строка критически к не делает работу запроса:
--Leading comment to thwart ADO from mangling MERGE on Windows XP/2003R2
MERGE Users
USING (VALUES ...
Кроме заявления, начиная с «с» для КТР функция также влияет! –
@ BerndOtt Это хорошая записка; и ужасающая реальность. Теперь я должен пройти еще один раунд обзора всего кода повсюду. :( –