6

我正在使用以下设置从 PHP 应用程序访问 MS-SQL 数据库

  • 红帽企业 Linux 5
  • 带有 PDO 和 PDO_ODBC 的 PHP 5.2.14
  • unixODBC 2.2.11
  • FreeTDS 0.82.1.dev.20100810

未参数化的查询工作正常。唯一的问题是被迫关闭单个结果语句上的游标(使用 PDOStatment::closeCursor)以避免“0 [FreeTDS][SQL Server] Invalid cursor state (SQLSTATE=24000)”错误。

但是我遇到了类型绑定参数的主要问题。使用这样的代码时:

$stmt = $PDO->prepare('INSERT INTO table (column1, column2)  VALUES (:foo, :bar');
$stmt->bindValue(':foo', 21, PDO::PARAM_INT);
$stmt->bindValue(':bar', 42, PDO::PARAM_INT);
$stmt->execute():
if (!$stmt->execute()) {
 var_dump($stmt->errorInfo();
}

其中两列都是 INT。我收到“206 [FreeTDS][SQL Server]操作数类型冲突:文本与 int [SQLSTATE=22018] 不兼容”错误。

在 unixODBC 日志中,我得到类似

[ODBC][26251][SQLDescribeParam.c][175]
              Entry:
                      Statement = 0x2b73c849fb80
                      Parameter Number = 1
                      SQL Type = 0x7fff9c89e15e
                      Param Def = 0x7fff9c89e154
                      Scale = 0x7fff9c89e15c
                      Nullable = 0x7fff9c89e15a
[ODBC][26251][SQLDescribeParam.c][276]Error: IM001
[ODBC][26251][SQLBindParameter.c][193]
              Entry:
                      Statement = 0x2b73c849fb80
                      Param Number = 1
                      Param Type = 1
                      C Type = 1 SQL_C_CHAR
                      SQL Type = -1 SQL_LONGVARCHAR
                      Col Def = 4000
                      Scale = 5
                      Rgb Value = 0x2b73c941f890
                      Value Max = 0
                      StrLen Or Ind = 0x2b73c93fa1b0
[ODBC][26251][SQLBindParameter.c][339]
              Exit:[SQL_SUCCESS]

我对日志的理解是 unixODBC 正在尝试使用正确的类型绑定参数。但是 FreeTDS 不支持该功能(IM001 是'驱动程序不支持此功能')。所以 unixODBC 在没有正确输入的情况下继续。

有人可以确认此诊断,或者更好的是 FreeTDS 中类型绑定参数的已知问题吗?如果是,它们是否使用 PHP PDO 工作,我可以配置它吗?

4

3 回答 3

6

我知道这是一个老问题,但我想为遇到同样问题的任何人发布我的解决方案。

我能够通过将我的 TDS 版本从 7.1 更改为 7.2 来解决此问题。我不再遇到任何问题。

希望这会有所帮助!

于 2012-03-07T21:40:53.377 回答
5

在 FreeTDS 邮件列表中,我得到了FreeTDS 不支持 SQLDescribeParam 的确认。但是当不支持 SQLDescribeParam 时,PDO_ODBC 是使用 LONGVARCHAR(即文本)的罪魁祸首

相同的代码在带有 PDO ODBC(PHP 版本 5.2.9,ODBC 库 Win32)的 Windows 工作站上工作

此问题的解决方法是将每个参数视为 LONGVARCHAR 并在查询中使用显式类型转换。MS SQL Server 仅支持 LONGVARCHAR => *CHAR 转换。要转换,我必须使用类似CAST(CAST(:number AS varchar) AS INTEGER)or的东西CAST(CAST(:birthdate AS varchar) AS datetime)。它很糟糕,很丑,而且可能是性能狂,但它确实有效

于 2010-10-04T08:56:56.317 回答
0

就我而言,我调用了一个存储过程,该过程返回记录......但其中有一些插入......我设法通过添加:

SET NOCOUNT ON

在您的插入情况下,这可能是相似的,因为 MSSQL 输出插入的结果,但 PDO 不理解它。

按你说的做演员对我没有用。

有关如何重现行为的示例:

create procedure sptest 
    @var int
as
begin 
    create table #tmp (var int)
    insert into #tmp values (@var)
    select * from #tmp
end

和 PHP 代码:

$query = "exec sptest @var=:var";
$dbh = new PDO (SQLSVR_DRIVER);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$rs = $dbh->prepare($query);
$rs->bindParam('var', 1, PDO::PARAM_INT);
$rs->execute();
while ($row = $rs->fetch(PDO::FETCH_ASSOC))
    var_dump($row);

修复方法是:

create procedure sptest 
    @var int
as
begin 
    set nocount on
    create table #tmp (var int)
    insert into #tmp values (@var)
    select * from #tmp
end

而已!

于 2013-09-23T06:46:16.930 回答