启用DataTypeCompatility时如何将12/30/1899参数化为SQL Server本机客户端?

问题描述 投票:5回答:1

短版

尝试将datetime12/30/1899传递给SQL Server,失败,显示无效的日期格式-但仅适用于本机客户端驱动程序,并且仅在DataTypeCompatiblity模式下。

长版

[当尝试针对SQL Server在ADO中使用参数化查询时:

SELECT ?

我将datetime值参数化为adDBTimeStamp

//Language agnostic, vaguely C#-like pseudo-code
void TestIt()
{
   DateTime dt = new DateTime("3/15/2020");
   VARIANT v = DateTimeToVariant(dt);

   Command cmd = new Command();
   cmd.CommandText = "SELECT ? AS SomeDate";
   cmd.Parameters.Append(cmd.CreateParameter("", adDBTimeStamp, adParamInput, 0, v);

   Connection cn = GetConnection();
   cmd.Set_ActiveConnection(cn);
   cmd.Execute(out recordsAffected, EmptyParam, adExecuteNoRecords);
}

并且当日期为3/15/2020时效果很好。

您创建一个VARIANT,其VARIANT为7(VType),并且该值是8字节浮点值:

VType

但是它在1899年12月30日失败

如果我在一个特定的日期时间执行相同的测试代码,它将失败:

VT_DATE

ADO OLEDB提供程序引发异常(即,甚至在到达SQL Server之前,它:]

VT_DATE

但是并非所有的SQL Server OLEDB提供程序都发生

调试此问题时,我意识到并不是所有的SQL Server OLEDB提供程序都发生这种情况。 Microsoft通常为SQL Server提供4个OLE DB提供程序:

  • [VARIANT Int32 vt = 7; //VT_DATE Double date = 0; :用于SQL Server的Microsoft OLE DB提供程序(自Windows 2000开始与Windows一起提供)]
  • void TestIt() { DateTime dt = new DateTime("12/30/1899"); VARIANT v = DateTimeToVariant(dt); Command cmd = new Command(); cmd.CommandText = "SELECT ? AS SomeDate"; cmd.Parameters.Append(cmd.CreateParameter("", adDBTimeStamp, adParamInput, 0, v); Connection cn = GetConnection(); cmd.Set_ActiveConnection(cn); cmd.Execute(out recordsAffected, EmptyParam, adExecuteNoRecords); } :SQL Server本机客户端(SQL Server 2005附带)
  • Invalid date format :SQL Server Native Client 11.0(SQL Server 2008附带)
  • SQLOLEDB:SQL Server Native Client 12.0(SQL Server 2012附带)
  • [SQLNCLI:用于SQL Server的Microsoft OLE DB驱动程序(SQL Server 2016附带)

[当与一些其他提供商一起尝试时,它does在某些情况下可以正常工作:

  • SQLNCLI10:作品
  • SQLNCLI11(无DataTypeCompatibility):有效
  • [MSOLEDBSQL(启用了DataTypeCompatiility的情况:失败)

DataTypeCompatibility?

是。 ActiveX数据对象(ADO)是不友好的COM OLEDB API的友好COM包装器,无法理解新的SQLOLEDBSQLNCLI11SQLNCLI11datetime数据类型。创建了新的OLEDB数据类型常量以表示这些新类型。因此,任何现有的OLEDB应用程序都无法理解新的常量。

为此,一个新的xml

  • datetime2

您可以将其添加到连接字符串中:

“ Provider = SQLNCLI11;数据源=螺丝刀;用户ID = hatguy;密码= hunter2; DataTypeCompatibility = 80;

这指示OLEDB驱动程序仅返回首次创建OLEDB时存在的OLEDB数据类型:

datetimeoffset

还有失败

何时:

  • 试图参数化keyword is supported by the "native" OLE DB drivers:
  • 值为DataTypeCompatibility=80
  • 使用“本地客户端”驱动程序时
  • 并且| SQL Server data type | SQLOLEDB | SQLNCLI | SQLNCLI | | | | | w/DataTypeCompatibility=80 | |----------------------|-----------------|--------------------------------|-----------------------------------| | Xml | adLongVarWChar | 141 (DBTYPE_XML) | adLongVarChar | | datetime | adDBTimeStamp | adDBTimeStamp | adDBTimeStamp | | datetime2 | adVarWChar | adDBTimeStamp | adVarWChar | | datetimeoffset | adVarWChar | 146 (DBTYPE_DBTIMESTAMPOFFSET) | adVarWChar | | date | adVarWChar | adDBDate | adVarWChar | | time | adVarWChar | 145 (DBTYPE_DBTIME2) | adVarWChar | | UDT | | 132 (DBTYPE_UDT) | adVarBinary (documented,untested) | | varchar(max) | adLongVarChar | adLongVarChar | adLongVarChar | | nvarchar(max) | adLongVarWChar | adLongVarWChar | adLongVarWChar | | varbinary(max) | adLongVarBinary | adLongVarBinary | adLongVarBinary | | timestamp | adBinary | adBinary | adBinary | 开启
  • 驱动程序本身使值窒息
  • 当它的值实际上很好时。

尝试使用日期'12 / 30 / 1899`并没有天生的错误:

  • datetime正常工作
  • 在原始的OLE DB驱动程序中正常工作
  • “ native” OLE DB驱动程序中工作正常
  • 12/30/1899启用的本机驱动程序中它只是失败,>
  • 显然,这是Microsoft OLE DB驱动程序中的错误。但是,微软绝对不会,ever

ever,EVER修复错误,这是绝对的事实。

那么如何解决呢?

我可以检测到这个特殊的日期时间,并且可以尝试在数据访问层中解决此错误。

  • 但是我需要一个可以放入DataTypeCompatilibty结构的值,
  • 代表SELECT CAST('18991230' AS datetime)
  • DataTypeCompatibility下有效
  • 并且在VARIANT xx驱动程序下
  • 并且在12/30/1899 12:00:00 AM驱动程序下
  • SQOLEDB
  • (还有什么鬼,即使关闭了模式-尽管在未启用ADO的情况下使用ADO都是无效的)
  • 驱动程序生成的T-SQL

当OLE DB驱动程序does费心去做我所说的事情时,我们可以分析生成的RPC:

SQOLEDB

SQLNCLI

SQLNCLI11

MSOLEDBSQL

CMRE(Delphi)

DataTypeCompatibilityMode

虽然这不是Delphi特有的问题;我正在使用Delphi。因此它被标记为Delphi。如果您抱怨exec sp_executesql N'SELECT @P1 AS SomeDate',N'@P1 datetime','1899-12-30 00:00:00'

Note

:这不是ADO.net,而是ADO。它不是托管的.NET Framework类库,它是本机Win32 COM OLE DB API。

简短版本尝试将日期时间值12/30/1899传递给SQL Server,但由于日期格式无效而失败-但仅适用于本机客户端驱动程序,并且仅适用于DataTypeCompatiblity模式。长版...

sql-server delphi oledb ado
1个回答
0
投票

BrakNicku回答了。

© www.soinside.com 2019 - 2024. All rights reserved.