php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #48924 int value > PHP_INT_MAX causes "Invalid text representation" in pdo_pgsql
Submitted: 2009-07-14 23:19 UTC Modified: 2009-07-16 22:57 UTC
From: mark dot kirkwood at catalyst dot net dot nz Assigned: felipe (profile)
Status: Closed Package: PDO related
PHP Version: 5.2CVS-2009-07-14 (CVS) OS: Ubuntu x86 (32 bit)
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: mark dot kirkwood at catalyst dot net dot nz
New email:
PHP Version: OS:

 

 [2009-07-14 23:19 UTC] mark dot kirkwood at catalyst dot net dot nz
Description:
------------
PDO performs conversions to string of various parameters. However for an integer > PHP_INT_MAX PHP has already converted it to a float before PDO sees it. This catches out Postgres [1] when inserting such a value because the conversion leaves trailing .0000... on the value.

Now this issue seems to have been fixed in PHP 6.0. The actual fix looks to be very simple (I'll attach a patch in a separate comment). The affected file is: 

ext/pdo/pdo_stmt.c

function:
really_register_bound_param

I think we can just call convert_to_string without any special casing for IS_DOUBLE, as convert_to_string handles them ok itself.

[1] but will catch Mysql too if have STRICT_ALL_TABLES or similar enabled.

Reproduce code:
---------------
 /* table a has desc (id bigint) */
 $sql = "INSERT INTO a VALUES (?)";
 $stmt = $dbh->prepare($sql,array(PDO::ATTR_EMULATE_PREPARES => true));
 $id = PHP_INT_MAX + 1;
 var_dump($id);
 $stmt->execute(array($id));


Expected result:
----------------
integer 2147483648 inserted into the table 'a'. 

Actual result:
--------------
PDOException: SQLSTATE[22P02]: Invalid text representation: 7 ERROR:  invalid input syntax for integer: "2147483648.000000"

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-07-14 23:23 UTC] mark dot kirkwood at catalyst dot net dot nz
Patch - merging the change from 6.0 to 5.2 (or 5.3 for that matter):
*** ext/pdo/pdo_stmt.c.orig 2009-07-14 18:07:23.000000000 +1200
--- ext/pdo/pdo_stmt.c  2009-07-15 11:20:58.000000000 +1200
***************
*** 327,339 ****
    }

    if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && ! ZVAL_IS_NULL(param->parameter)) {
!       if (Z_TYPE_P(param->parameter) == IS_DOUBLE) {
!           char *p;
!           int len = spprintf(&p, 0, "%F", Z_DVAL_P(param->parameter));
!           ZVAL_STRINGL(param->parameter, p, len, 0);
!       } else {
!           convert_to_string(param->parameter);
!       }
    } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && Z_TYPE_P(param->parameter) == IS_BOOL) {
        convert_to_long(param->parameter);
    } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && Z_TYPE_P(param->parameter) == IS_LONG) {
--- 327,333 ----
    }

    if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && ! ZVAL_IS_NULL(param->parameter)) {
!       convert_to_string(param->parameter);
    } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && Z_TYPE_P(param->parameter) == IS_BOOL) {
        convert_to_long(param->parameter);
    } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && Z_TYPE_P(param->parameter) == IS_LONG) {
 [2009-07-15 00:38 UTC] mark dot kirkwood at catalyst dot net dot nz
Re: my footnote for Mysql - actually it does *not* elicit a similar error with strict mode on.Sorry, my confusion.
 [2009-07-15 23:14 UTC] felipe@php.net
I can't reproduce it on PostgreSQL with libpq5 (8.3.7).
 [2009-07-15 23:24 UTC] mark dot kirkwood at catalyst dot net dot nz
Are you using a 32bit os? If you turn on statement logging you should see an insert that looks like:

INSERT INTO a VALUES('2147483648.000000')
 [2009-07-16 01:07 UTC] felipe@php.net
Yes, it's 32 bit OS.
I just got an expected error "out of range".

I've commited a patch [1] that remove the trailing zeros, please let me know if it fixes your case.

About the HEAD version, It currently doesn't contains the fix (the code which introduced the trailing zeros) for #41698.

[1] http://felipe.ath.cx/diff/bug48924.diff
 [2009-07-16 01:24 UTC] mark dot kirkwood at catalyst dot net dot nz
Hmm - if you are getting out of range, then that sounds like your table has the wrong definition - it should be created by:

CREATE TABLE a (id bigint)

so that 2147483648 can actually be inserted. I can replicate what you are seeing by creating a with 'id integer'.

Having said that, it looks to me like your patch fixes the problem, but I only have a 64 bit system here at work, so I'm cheating by doing:

//$id = PHP_INT_MAX + 1;
$id = (float)2147483648;

I'll check on a 32-bit system tonight to be sure and report back. Thanks for the fast response!
 [2009-07-16 08:54 UTC] mark dot kirkwood at catalyst dot net dot nz
Rechecked at home on a 32 bit os, and confirmed that your patch fixes the issue. Nice work, and thanks again for a very fast resolution.
 [2009-07-16 22:57 UTC] felipe@php.net
Thanks for reporting & testing.

Committed in 5.2, 5.3 and HEAD.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 14:01:32 2024 UTC