Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/253.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php ';PDO异常';带有消息';SQLSTATE[22001]:字符串数据,右截断:0_Php_Sql Server_Pdo_Odbc_Prepared Statement - Fatal编程技术网

Php ';PDO异常';带有消息';SQLSTATE[22001]:字符串数据,右截断:0

Php ';PDO异常';带有消息';SQLSTATE[22001]:字符串数据,右截断:0,php,sql-server,pdo,odbc,prepared-statement,Php,Sql Server,Pdo,Odbc,Prepared Statement,注意:我已经把这个问题缩小到专门的PDO,因为我能够使用函数成功地准备和执行语句 为什么我不能将这个参数绑定到PDO准备好的语句 这项工作: $mssqldriver = 'ODBC Driver 13 for SQL Server'; $pdoDB = new PDO("odbc:Driver=$mssqldriver;Server=$hostname;Database=$dbname", $username, $password); $pdoDB->setAttribute( PDO:

注意:我已经把这个问题缩小到专门的PDO,因为我能够使用函数成功地准备和执行语句

为什么我不能将这个参数绑定到PDO准备好的语句

这项工作:

$mssqldriver = 'ODBC Driver 13 for SQL Server';
$pdoDB = new PDO("odbc:Driver=$mssqldriver;Server=$hostname;Database=$dbname", $username, $password);
$pdoDB->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

$sql = "SELECT 'value' AS col where 'this' = 'this'";
$stmt = $pdoDB->prepare($sql);
$params = [];
$stmt->execute($params);
print_r($stmt->fetch());
不起作用:

$sql = "SELECT 'value' AS col where 'this' = ?";
$stmt = $pdoDB->prepare($sql);
$params = ['this'];
$stmt->execute($params);
print_r($stmt->fetch());
$sql = "SELECT * FROM myTable WHERE val = ?";
$stmt = $pdoDB->prepare($sql);
$params = ['hello world'];
$stmt->execute($params);
print_r($stmt->fetch());
Web服务器在Linux Ubuntu 14.04上运行PHP5.5.9,带有SQL Server的ODBC驱动程序13,并连接到Windows Server 2012上的Microsoft SQL Server 2012

以下是全部错误:

我还尝试设置:

$pdoDB->setAttribute( PDO::ATTR_EMULATE_PREPARES, true );
并使用命名参数:

$sql = "SELECT 'value' AS col where 'this' = :myVal";
$stmt = $pdoDB->prepare($sql);
$params = ['myVal' => 'this'];
$stmt->execute($params);
print_r($stmt->fetch());
$sql = "SELECT 'value' AS col where 'this' = :myVal";
$stmt = $pdoDB->prepare($sql);
$param = 'this';
$stmt->bindParam(':myVal', $param, PDO::PARAM_STR);
$stmt->execute();
print_r($stmt->fetch());
即使使用显式冒号:

$params = [':myVal' => 'this'];
我还尝试了使用,如中所示:

以及命名参数:

$sql = "SELECT 'value' AS col where 'this' = :myVal";
$stmt = $pdoDB->prepare($sql);
$params = ['myVal' => 'this'];
$stmt->execute($params);
print_r($stmt->fetch());
$sql = "SELECT 'value' AS col where 'this' = :myVal";
$stmt = $pdoDB->prepare($sql);
$param = 'this';
$stmt->bindParam(':myVal', $param, PDO::PARAM_STR);
$stmt->execute();
print_r($stmt->fetch());
如果我尝试显式设置长度:

$stmt->bindParam(':myVal', $param, PDO::PARAM_STR, 4);
我得到一个额外的错误:

是的,所有这些都是一个没有表格的小例子,所以你可以很容易地复制它,但为了确定,我实际上已经用一个真实的表格尝试过了

创建表myTable(
id INT标识主键,
瓦尔·纳瓦尔(255)
);
插入myTable(val)值(“hello world”);
作品:

$sql = "SELECT * FROM myTable WHERE val = 'hello world'";
$stmt = $pdoDB->prepare($sql);
$params = [];
$stmt->execute($params);
print_r($stmt->fetch());
不起作用:

$sql = "SELECT 'value' AS col where 'this' = ?";
$stmt = $pdoDB->prepare($sql);
$params = ['this'];
$stmt->execute($params);
print_r($stmt->fetch());
$sql = "SELECT * FROM myTable WHERE val = ?";
$stmt = $pdoDB->prepare($sql);
$params = ['hello world'];
$stmt->execute($params);
print_r($stmt->fetch());
所有路径都会导致相同的错误:

字符串数据,右截断


这可能不是您想要听到的,但这具有PHP的ODBC PDO驱动程序(由于PHP程序员倾向于使用MySQL/SQLite/Postgres等开源数据库而不是商业产品)或底层SQL server驱动程序(由于类似原因,Linux对其支持不足)中的所有缺陷特征,但如果odbc_*正常工作,那么它可能不是底层驱动程序

如果您尝试执行完全相同的任务,除了使用
“sqlite::memory:”
作为DSN之外,所有示例都可以工作。这使得您很可能没有做错任何事情(除非MS Server有一些我不知道的非常奇怪的不符合SQL语法)。当启用和禁用了
ATTR\u EMULATE\u PREPARES
时,您的示例对我使用SQLite非常有用

我认为你能现实地做的就是希望有人捡起它。不过你可能要等很长时间

至于问题的实际解决方案,您可以选择a)切换到PHP支持的DBMS,或者b)使用SQL字符串构造,而不是预先准备好的语句,并准备好接受避免自己的负担。不过,这应该被视为最后的手段!使用可能会有所帮助,但我也会确保您的数据也经过彻底验证。我知道这不是一个理想的解决方案,但如果您必须使用MS SQL,并且迫不及待地等待PHP团队对其进行错误修复,那么我真的看不出您有多少选择

或者有一个选项c),如果odbc_*函数有效的话,可以使用它。当然,如果您想使用OOP风格,那么您必须实现自己的类,该类将过程odbc函数包装在OO方法中,因此可能需要大量的工作

编辑:我发现询问者似乎有类似的问题。他的解决方案是抛弃“官方”MS司机,转而选择FreeTDS。这可能有点像是在黑暗中拍摄,但值得一试

不幸的是, 这是一个
PDO_ODBC
64位不兼容问题(,),毫无疑问,您使用的是64位构建,不允许绑定参数

幸运的是, 这首先包含在5.6版本中:

此错误也在中引用 现在还在 在5.5分支的最新稳定版本中。我看到两张票 这个问题已经存在,我正在提交这些更改 通过github提醒大家,这对任何人来说都是一个严重的问题 在x64版本上使用
PDO_ODBC

PHP附带的
PDO_ODBC
有什么问题? 通过查看其中一个推荐的修补程序:

diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c
index 8b0ccf3..1d275cd 100644
--- a/ext/pdo_odbc/odbc_stmt.c
+++ b/ext/pdo_odbc/odbc_stmt.c
@@ -551,7 +551,7 @@ static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
    struct pdo_column_data *col = &stmt->columns[colno];
    RETCODE rc;
    SWORD   colnamelen;
-   SDWORD  colsize;
+   SQLULEN colsize;
    SQLLEN displaysize;
我们看到唯一改变的是
SDWORD
(16位有符号整数),它被新的ODBC类型
SQLULEN
取代

我相信提交人只知道
colsize
数据类型,因为在下一行中
SQLLEN
定义正确

我现在该怎么办?
  • 升级至PHP版本>=5.6
  • 坚持使用
    odbc.*
    函数作为工作解决方案
  • 使用提供的补丁编译PHPV5.5.9
  • 按照@GordonM的建议构建您自己的PDO包装器

  • 您是否启用了ATTR\u仿真\u准备?如果你改变它会有什么不同吗?如果使用命名参数,如
    选择:param as col
    和bind
    [':param'=>'test']
    ,是否会有区别?我不希望有任何改变…@MichaelBerkowski我只是尝试了这两种方法,但都没有效果-相同的错误。“this”字段是什么类型?@zajonc它是字符串文字,因此其他人可以轻松复制,而无需数据集。我的实际用例涉及一个NVARCHAR(255),但我无法使它适用于任何数据类型。我想这完全是DBMS的问题,与PDO关系不大。出于好奇,您是否也可以复制所有静态查询?我的意思是,
    'this'='this'
    ?WOW64824也是我的一个bug。我垂涎你的Google Fu,因为我从未接近找到它。我担心这个补丁是为61777中引用的一个稍有不同的bug构建的,但我仍然渴望尝试。我可能需要几天时间来启动一个测试虚拟机,用这个补丁构建定制PDO,但我很兴奋,谢谢!我将该补丁与PHP7.0相关的源文件进行了比较,可以说您将做得很好@Jeffpuckettititoday我在带有php7的vm上安装了一个新的ubuntu 16.04,并确认这个问题不存在。我编辑了您的答案以包含此选项。明天我将用php5启动另一个vm,并用补丁编译以完全确认您的答案,如果成功,那么我将高兴
    diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c
    index 8b0ccf3..1d275cd 100644
    --- a/ext/pdo_odbc/odbc_stmt.c
    +++ b/ext/pdo_odbc/odbc_stmt.c
    @@ -551,7 +551,7 @@ static int odbc_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
        struct pdo_column_data *col = &stmt->columns[colno];
        RETCODE rc;
        SWORD   colnamelen;
    -   SDWORD  colsize;
    +   SQLULEN colsize;
        SQLLEN displaysize;