Bug #80637 [Opn->Ver]: bindParam() changes type property to string
| From: | cmb@php.net | Date: | Tue, 08 Jun 2021 13:23:50 +0000 |
| Subject: | Bug #80637 [Opn->Ver]: bindParam() changes type property to string | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-234261@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=80637&edit=1
ID: 80637
Updated by: cmb@php.net
Reported by: php at evilazrael dot de
Summary: bindParam() changes type property to string
-Status: Open
+Status: Verified
Type: Bug
Package: PDO Core
-Operating System: Linux
+Operating System: *
PHP Version: 7.4.14
Block user comment: N
Private report: N
New Comment:
> According to comments on bindParam() this is the normal
> behaviour for at least 11 years, [â¦]
That info is also in the manual proper:
| Most parameters are input parameters, that is, parameters that
| are used in a read-only fashion to build up the query (but may
| nonetheless be cast according to $type).
However, I can confirm that PDOStatement::bindParam() and
::bindColumn() are not prepared to work with typed properties,
since they directly convert the parameter to the $type[1]. This
appears to be fixable; minimal PoC for the given case attached.
Still, when the actual binding at the DB API level happens, the
parameter has to be bound according to the given type, see e.g.
the respective PDO_SQLITE implementation[2]. To properly support
typed properties, we would need to bind a temporary zval, and to
assign that back to the original zval on PDO_PARAM_EVT_EXEC_POST.
The temporary zval would need to be stored in the respective
struct pdo_bound_param_data variable, what *might* constitute an
ABI break.
Another option to fix this issue would be to reject potentially
incompatible bindings in ::bindParam() and ::bindColumn() right
away. That would, however, impose strict type semantics, and such
constitute an inconsistency, and a BC break for coercive type
mode. It had, however, the advantage that the fundamental
invariant of typed properties would not be violated, regardless of
individual PDO drivers being fixed.
Not sure how to proceed here.
[1] <https://github.com/php/php-src/blob/php-7.4.20/ext/pdo/pdo_stmt.c#L301-L322>
[2] <https://github.com/php/php-src/blob/php-7.4.20/ext/pdo_sqlite/sqlite_statement.c#L135-L233>
Previous Comments:
------------------------------------------------------------------------
[2021-06-08 13:23:39] cmb@php.net
The following patch has been added/updated:
Patch Name: bindparam-typed-props
Revision: 1623158619
URL: https://bugs.php.net/patch-display.php?bug=80637&patch=bindparam-typed-props&revision=1623158619
------------------------------------------------------------------------
[2021-01-26 12:17:12] cmb@php.net
@nikic: oops!
------------------------------------------------------------------------
[2021-01-19 13:22:19] nikic@php.net
@cmb: You didn't use the right property there: https://3v4l.org/tXjhi
------------------------------------------------------------------------
[2021-01-19 12:44:06] cmb@php.net
There appears to be a more general issue:
<https://3v4l.org/F6pnT>.
------------------------------------------------------------------------
[2021-01-17 19:45:52] php at evilazrael dot de
Description:
------------
Nothing new, but still unexpected. bindParam() changes the bound variable to type string. According
to comments on bindParam() this is the normal behaviour for at least 11 years, but with the typed
property support introduced in 7.4 this is even more unexpected to have an int property containing a
string, something you can do directly.
I tested this with SQLite and PostgreSQL and seems to be independent of the used database.
Test script:
---------------
<?php
class TestClass
{
public int $a;
}
$x = new TestClass;
$x->a = 17;
var_dump($x);
/*
class TestClass#3 (1) {
public int $a =>
int(17)
}
*/
$db = new PDO("sqlite::memory:");
$stmt = $db->prepare("SELECT :val");
$stmt->bindValue(":val", $x->a);
$stmt->execute();
$stmt->closeCursor();
var_dump($x);
/*
class TestClass#3 (1) {
public int $a =>
int(17)
}
*/
$stmt->bindParam(":val", $x->a);
$stmt->execute();
$stmt->closeCursor();
var_dump($x);
/*
class TestClass#3 (1) {
public int $a =>
string(2) "17"
}
*/
Expected result:
----------------
Int typed property containing an int value
Actual result:
--------------
Int typed property containing a string.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=80637&edit=1