Совместимость с типом данных собственного клиента SQL - несовместима с SQLOLEDB
Мы столкнулись с проблемой с нашим унаследованным приложением при переходе на использование собственного клиента SQL (SQLNCLI) в качестве поставщика ADO.
Наша оригинальная строка подключения была:
Provider=SQLOLEDB; Server=host; Database=bob; Integrated Security=SSPI;
мы изменили это на:
Provider=SQLNCLI11; Server=host; Database=bob; Integrated Security=SSPI; DataTypeCompatibility=80;
Мы обнаружили, что при вызове хранимой процедуры с использованием параметра adDBTimeStamp собственный клиент обрабатывает метку времени как маленькое время, а не как дату. Это вызывает у нас проблемы, так как мы используем 31 декабря 9999 года в качестве "верхней" даты в некоторых сравнениях, и собственный клиент завершается с ошибкой "Неверный формат даты", когда у SQLOLEDB не было проблем.
Теперь, похоже, мы можем просто сменить adDBTimeStamp на adDate в качестве типа данных при создании параметра, однако мне было интересно, не было ли чего-то, чего нам не хватало в строке соединения, прежде чем мы продолжим работу и внесем изменения в код.
Код VBScript для воспроизведения ниже. Во избежание сомнений, формат даты - Великобритания (дд / мм / гггг), прежде чем кто-то предложит нам использовать его 12/31/9999:-) Но также для подтверждения, CDate не подведет.
Set db = CreateObject("ADODB.Command")
' If Provider=SQLOLEDB then there is no error.
db.ActiveConnection = "Provider=SQLNCLI11; Server=host; Database=bob; Integrated Security=SSPI; DataTypeCompatibility=80;"
db.CommandText = "usp_FetchData"
db.CommandType = &H0004
' 135 is adDBTimeStamp
db.Parameters.Append db.CreateParameter("@screenDate", 135, 1, 20, CDate("31/12/9999"))
Set rs = CreateOBject("ADODB.RecordSet")
' Then this line fails with "Invalid date format" from SQLNCLI
rs.Open db
WScript.Echo rs.RecordCount
Обращение даты и времени назад к 2078 (в пределах диапазона дат smalldatetime) устраняет ошибку.
Как уже упоминалось, если можно найти исправление без изменения кода, это то, что мы бы предпочли, прежде чем мы перейдем к замене adDBTimeStamp на adDate. Я ожидал бы, что DataTypeCompatiblity=80 будет вести себя как SQLOLEDB; К сожалению, мой Google-фу не удался, когда выяснил, какое именно отображение типов использует SQLNCLI.
1 ответ
Решение, наконец, может быть найдено: через страницу MSDN Поддержка типов данных для улучшений даты и времени OLE DB есть следующий фрагмент к концу:
Отображение типов данных в ITableDefinition::CreateTable
Следующее сопоставление типов используется со структурами DBCOLUMNDESC, используемыми ITableDefinition::CreateTable:
[... таблица преобразований...]
Когда приложение указывает DBTYPE_DBTIMESTAMP в wType, оно может переопределить отображение на datetime2, указав имя типа в pwszTypeName. Если указано datetime, bScale должно быть 3. Если указано smalldatetime, bScale должно быть 0. Если bScale не соответствует wType и pwszTypeName, возвращается DB_E_BADSCALE.
При тестировании оказывается, что необходимо установить масштаб, применяемый к параметрам для SELECT и команд, а также для CreateTable. Поэтому, если мы изменим скрипт выше:
Set param = db.CreateParameter("@screenDate", 135, 1, 20, CDate("31/12/9999"))
param.NumericScale = 3
db.Parameters.Append param
... затем ошибка исчезает и хранимая процедура выполняется. Мы находимся на ранних этапах тестирования, однако приветствуем отзывы других, если это вызвало проблемы.