Ошибки в SQL Server при передаче даты '12/30/1899': проблемы и решения через ADO и DataTypeCompatibility
При работе с базой данных SQL Server через ActiveX Data Objects (ADO) и использовании параметризованных запросов может возникнуть проблема с передачей даты '12/30/1899'. Эта дата имеет особое значение в OLE Automation и в частности в структуре VARIANT, используемой в ADO. В некоторых случаях, при использовании драйверов SQL Server Native Client (SQLNCLI) и включенном режиме DataTypeCompatibility, может возникать ошибка "Недопустимый формат даты".
Проблема
При попытке использовать параметризованный запрос с datetime значением '12/30/1899' через ADO и драйверы SQL Server Native Client, в режиме DataTypeCompatibility, возникает исключение с сообщением "Недопустимый формат даты". Это происходит до того, как запрос достигает SQL Server, и связано с самой реализацией драйверов.
Решение
Для решения этой проблемы необходимо изменить способ передачи параметра даты. Вместо использования типа adDBTimeStamp, следует установить свойство NumericScale параметра в диапазоне 1-7, что позволит драйверу интерпретировать параметр как datetime2, а не smalldatetime.
Parameter p = cmd.CreateParameter("", adDBTimeStamp, adParamInput, 0, v);
p.NumericScale = 1; // или любое другое значение от 1 до 7
Такой подход позволяет избежать ошибки и успешно выполнить параметризованный запрос.
Альтернативное решение
В качестве альтернативы, можно использовать передачу datetime значений в виде строк в формате ODBC 24-часового времени, например adVarChar с использованием формата yyyy-mm-dd hh:mm:ss.zzz.
Пример кода на Object Pascal (Delphi)
program ParameterizedQuery;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
ComObj,
ActiveX,
ADOdb,
ADOint,
Variants;
function GetConnection(ProviderName: string; DataTypeCompatibility: Boolean): _Connection;
var
connectionString: string;
begin
connectionString := 'Provider=' + ProviderName + ';Data Source=...;';
if DataTypeCompatibility then
connectionString := connectionString + 'DataTypeCompatibility=80;';
Result := CoConnection.Create;
Result.Open(connectionString, '', '', adConnectUnspecified);
end;
procedure TestDateParameter(ProviderName: string; DataTypeCompatibility: Boolean);
var
dt: TDateTime;
v: OleVariant;
cmd: _Command;
cn: _Connection;
recordsAffected: OleVariant;
begin
dt := EncodeDate(1899, 12, 30); // 12/30/1899 12:00:00 AM (нулевая дата в Delphi)
v := dt; // Тип variants - VT_DATE (7)
cmd := CoCommand.Create;
cmd.CommandText := 'SELECT ? AS SomeDate';
with cmd.CreateParameter('', adDBTimeStamp, adParamInput, 0, 0) do
begin
SetDataType(adDBTimeStamp);
SetNumericScale(1); // Установка свойства NumericScale
cmd.Parameters.Append(Self);
end;
cmd.Parameters[0].PutValue(v);
try
cn := GetConnection(ProviderName, DataTypeCompatibility);
except
on E: Exception do
begin
Writeln('Provider ' + ProviderName + ' не установлен: ' + E.Message);
Exit;
end;
end;
cmd.Set_ActiveConnection(cn);
try
cmd.Execute({out}recordsAffected, EmptyParam, adExecuteNoRecords);
Writeln('Provider ' + ProviderName + ' (DataTypeCompatibility=' + (DataTypeCompatibility: 'with': 'without') + '): success.');
except
on E: Exception do
begin
Writeln('Provider ' + ProviderName + ' (DataTypeCompatibility=' + (DataTypeCompatibility: 'with': 'without') + ') failed: ' + E.Message);
end;
end;
end;
begin
CoInitialize(nil);
TestDateParameter('SQLOLEDB', False);
TestDateParameter('SQLNCLI11', False);
TestDateParameter('SQLNCLI11', True);
// ... аналогично для других доступных драйверов
end.
Заключение
При работе с SQL Server через ADO и параметризованные запросы важно учитывать особенности работы с датами, особенно при использовании режима DataTypeCompatibility и драйверов SQL Server Native Client. Установка свойства NumericScale для параметра типа adDBTimeStamp позволяет избежать ошибок при передаче даты '12/30/1899'.
Проблема и решения связаны с особенностями передачи даты '12/30/1899' в SQL Server через ADO и настройками режима DataTypeCompatibility.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.