'PDOException' with message 'SQLSTATE[22001]: String data, right truncated: 0

久未见 提交于 2019-11-27 22:45:01

Unfortunately,

It's a PDO_ODBC 64-bit incompatibility problem (#61777, #64824) and without any doubts you are on a 64-bit build which doesn't allow you to bind parameters.

Fortunately,

It has a patch that was first included in the 5.6 release:

This bug is also referenced in #61777 and is still present in the latest stable release of the 5.5 branch. I see two tickets exist for this problem already, and I'm just submitting these changes via github as a reminder that this is a serious problem for anyone using PDO_ODBC on the x64 builds.

What is wrong with your PHP's shipped PDO_ODBC?

By looking at one of those recommended patches:

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;

We see the only thing that's changed is SDWORD (16-bit signed integer) which is substituted with new ODBC type SQLULEN that is 64 bits in a 64-bit ODBC application and 32 bits in a 32-bit ODBC application.

I believe committer wasn't aware of colsize data type only since in the very next line SQLLEN is defined properly.

What should I do now?

  1. Upgrade to PHP version >= 5.6
  2. Stick with odbc_* functions as a working solution.
  3. Compile a PHP v5.5.9 with provided patches.
  4. Build your own PDO wrapper as recommended by @GordonM
GordonM

This is probably not what you want to hear, but this has all the hallmarks of a bug in PHP's ODBC driver for PDO (which is not heavily used as PHP programmers tend to favour open source databases like MySQL/SQLite/Postgres over commercial offerings), or in the underlying SQL server driver (which is poorly supported in Linux, for similar reasons), though if odbc_* works then it's probably not the underlying driver.

If you try to do the exact same tasks, except using "sqlite::memory:" as the DSN, all your examples work. This makes it highly unlikely that you're doing anything wrong (unless MS Server has some really weird non-conforming SQL syntax of which I'm not aware). Your examples work fine for me with SQLite when ATTR_EMULATE_PREPARES is both enabled and disabled.

All I think you can realistically do is file a bug report and hope somebody picks it up. You may be in for a long wait though.

As for practical solutions to your problem, your options are either a) switch to a DBMS that PHP supports or b) resort to SQL string construction instead of prepared statements and be ready to accept the burden of avoiding SQL injection attacks yourself. This should be considered a last resort though! Using PDO::quote() may help but I'd also make sure your data is very thoroughly validated as well. I know it's not an ideal solution, but if you must use MS SQL and can't wait for the PHP team to bugfix it then I don't really see that you have much of a choice.

Or there's option c) which is use odbc_* functions instead, if they work. Of course if you want to use OOP style then you'll have to implement your own class that wraps the procedural odbc functions in OO methods so that could potentially be a lot of work.

EDIT: I found another question on Stack Overflow where the asker seems to have a similar problem. His solution was to ditch the "official" MS driver in favour of FreeTDS. This might be something of a shot in the dark, but it could be worth a try.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!