php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #54023 PDO prepared statements using SQLite can't bind non-text values in expressions
Submitted: 2011-02-15 11:46 UTC Modified: 2018-07-27 15:14 UTC
Votes:4
Avg. Score:3.8 ± 0.8
Reproduced:4 of 4 (100.0%)
Same Version:1 (25.0%)
Same OS:3 (75.0%)
From: sl9 at gmx dot net Assigned:
Status: Open Package: PDO SQLite
PHP Version: 5.3SVN-2011-02-15 (SVN) OS: Linux i386
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: sl9 at gmx dot net
New email:
PHP Version: OS:

 

 [2011-02-15 11:46 UTC] sl9 at gmx dot net
Description:
------------
This report is an addition to / repost of the bug reported in #45259 from 2008. I replied on that one a few weeks ago but nobody seemed to take notice.
This bug seems to also have been reported in bug #53475 (2010).

It concerns: When using PDO with the SQLite backend and prepared SQL statements, it appears to be impossible to bind anything but a text or NULL value to a parameter.

As a remark I would like to mention, binded values other than string and NULL types are cast to a string automatically.

The bug is explained quite well in bug #45259. And I've added a patch only for the 5.3 branch as that has support for the PHP_PARAM_ZVAL type (which 5.2 lacks apparently). The current patch will not easily be backported to 5.2, I think.

I've tested the patch below with the svn commit I could grab today (308350). It includes a couple of test cases which should cover the bug quite well.

Test script:
---------------
$dbase = new PDO('sqlite::memory:');

$stmt = $dbase->prepare('SELECT 1=? AS result');
$stmt->execute(array(1));
echo '(INT == BOUNDINT)    = ', ($stmt->fetchColumn() == 1 ? 'true' : 'false'), PHP_EOL;

$stmt = $dbase->prepare('SELECT "1"=? AS result');
$stmt->execute(array(1));
echo '(STRING == BOUNDINT) = ', ($stmt->fetchColumn() == 1 ? 'true' : 'false'), PHP_EOL;

Expected result:
----------------
(INT == BOUNDINT)    = true
(STRING == BOUNDINT) = false

Actual result:
--------------
(INT == BOUNDINT)    = false
(STRING == BOUNDINT) = true

Patches

bug45259_sqlite-bind-params-autodetect_v308350 (last revision 2011-02-15 10:47 UTC by sl9 at gmx dot net)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-02-15 11:50 UTC] sl9 at gmx dot net
Original patch notes from #45259

I have experienced this bug also. I tried most of the windows builds which are available on the download page: 5.3.4 (ts and nts, vc6 and vc9) and 5.2.16 (ts and nts).

My tests try to execute a prepared statement with parameters and what I'd like PDO to do is map my php variable to a PDO_PARAM_* type. This is where things go wrong.

Example:
$db = new PDO('sqlite::memory:');

$stmt = $db->prepare('SELECT "string" = ? AS test');
$stmt->execute(array('string'));
$row = $stmt->fetch();
echo 'test: ', $row['test'], PHP_EOL;
// prints "test: 1", I expect "test: 1"

$stmt = $db->prepare('SELECT 50 = ? AS test');
$stmt->execute(array(50));
$row = $stmt->fetch();
echo 'test: ', $row['test'], PHP_EOL;
// prints "test: 0", I expect "test: 1"

The strange thing is:
$stmt = $db->prepare('SELECT 50 = 50 AS test');
$stmt->execute();
$row = $stmt->fetch();
echo 'test: ', $row['test'], PHP_EOL;
// prints "test: 1", I expect "test: 1"

This indicates sqlite knows what I mean, but somewhere in PDO things go bump.

I've investigated by looking into the source (SVN 5.3 rev 306430 from yesterday on a fresh Debian lenny install). And devised a few test cases and a patch. In the pdo_sqlite extension it all works peachy, although for the mapping of ZVAL to PDO_PARAM_* I've had to edit the pdo_stmt.c file in the pdo extension. I don't know if this is acceptable as I can imagine many drivers depend on the pdo extension being frozen.

I've added an exception to the PDOStatement::execute() handler, the handler sets the default PDO_PARAM_* to PDO_PARAM_ZVAL to signal that no explicit type was set. So the driver can do it's own mapping. This only takes effect when the driver for the statment is sqlite. Others might depend on the default to be PDO_PARAM_STR.
This cannot stay PDO_PARAM_STR because really_register_bound_param() will try and autoconvert the ZVAL if it is PDO_PARAM_STR or a couple of other param types. I assume this will destroy the original ZVAL's type and will make it indistinguishable from an explicitly defined PDO_PARAM_STR param.

So now the pdo_sqlite_stmt_param_hook() will receive a parameter with PDO type PDO_PARAM_ZVAL when it is not explicitly set by the user, this will allow the driver to inspect the given zval and bind it accordingly. This has also been included in the patch which are alterations of only the pdo_sqlite_stmt_param_hook() function. I've revised it a bit, it looked odd to me all those return statements scattered throughout the nested switch statements.

I've only tested this with the SVN build from yesterday on Debian lenny x86. Maybe we should test it on more platforms? And can someone comment on the patch, especially if we can merge it into the svn 5.3 branch?
 [2014-01-01 12:46 UTC] felipe@php.net
-Package: PDO related +Package: PDO SQLite
 [2018-07-27 15:14 UTC] cmb@php.net
-Type: Bug +Type: Feature/Change Request
 [2018-07-27 15:14 UTC] cmb@php.net
Behavior confirmed: <https://3v4l.org/LsC9s>.

However, I don't think this is a bug (since it's possible to call
::bindValue() explicitly), but rather a missing feature.  Given
that a special casing in PDOStatement is suggested, discussion on
the internals@ mailing appears to be appropriate.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Mar 19 05:01:29 2024 UTC