Bug #65946 [PATCH]: pdo_sql_parser.c permanently converts values bound to strings

From: Date: Thu, 07 Nov 2013 17:54:27 +0000
Subject: Bug #65946 [PATCH]: pdo_sql_parser.c permanently converts values bound to strings
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-182631@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=65946&edit=1

 ID:                 65946
 Patch added by:     rasmus@php.net
 Reported by:        jakub dot lopuszanski at nasza-klasa dot pl
 Summary:            pdo_sql_parser.c permanently converts values bound
                     to strings
 Status:             Assigned
 Type:               Bug
 Package:            PDO related
 Operating System:   debian
 PHP Version:        Irrelevant
 Assigned To:        willfitch
 Block user comment: N
 Private report:     N

 New Comment:

The following patch has been added/updated:

Patch Name: bug65946.diff
Revision:   1383846867
URL:        https://bugs.php.net/patch-display.php?bug=65946&patch=bug65946.diff&revision=1383846867


Previous Comments:
------------------------------------------------------------------------
[2013-11-07 03:49:26] willfitch@php.net

Confirmed in 5.5.

------------------------------------------------------------------------
[2013-10-22 13:53:55] jakub dot lopuszanski at nasza-klasa dot pl

Description:
------------
When a bindValue is used to bind a a PARAM_INT, then the first time execute() is called the value is
inserted into query without quotes, but the second time it is called the value gets surrounded with
quotes. This can obviously trigger MySQL parse errors if the placeholder is used in a position where
a number must be used (for example in LIMIT :limit).

I suspect that the reason for that behaviour is that in pdo_parse_params method in pdo_sql_parser.c
there is a switch statement with side effects:

                    switch (Z_TYPE_P(param->parameter)) {
                        case IS_NULL:
                            plc->quoted = "NULL";
                            plc->qlen = sizeof("NULL")-1;
                            plc->freeq = 0;
                            break;

                        case IS_BOOL:
                            convert_to_long(param->parameter);

                        case IS_LONG:
                        case IS_DOUBLE:
                            convert_to_string(param->parameter);
                            plc->qlen = Z_STRLEN_P(param->parameter);
                            plc->quoted = Z_STRVAL_P(param->parameter);
                            plc->freeq = 0;
                            break;

                        default:
                            convert_to_string(param->parameter);
                            if (!stmt->dbh->methods->quoter(stmt->dbh,
Z_STRVAL_P(param->parameter),
                                    Z_STRLEN_P(param->parameter), &plc->quoted,
&plc->qlen,
                                    param->param_type TSRMLS_CC)) {
                                /* bork */
                                ret = -1;
                                strncpy(stmt->error_code, stmt->dbh->error_code, 6);
                                goto clean_up;
                            }
                            plc->freeq = 1;
                    }

in parcitular, it seems to me that when this switch is visited the first time, then the value is
treated as IS_LONG, and convert_to_string is applied to it.
The next time it is already a string so it falls into the "default" category, and
therefore gets treated with stmt->dbh->methods->quoter.


Test script:
---------------
//$db must be a MySQL database
$q=$db->prepare('SELECT * FROM test LIMIT :limit');
$q->bindValue('limit',1,PDO::PARAM_INT);
$q->execute();
$q->execute();



Expected result:
----------------
script not failing

Actual result:
--------------
PHP Fatal error:  Uncaught exception 'PDOException' with message 'SQLSTATE[42000]:
Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near ''1''
at line 1' in  ...


------------------------------------------------------------------------



-- 
Edit this bug report at https://bugs.php.net/bug.php?id=65946&edit=1


Thread (6 messages)

« previous php.bugs (#182631) next »