user2875878
user2875878

Reputation: 33

PDO query binding string instead of integer returns results

I have a table with and auto increment id and was just testing a few scenarios when I stumbled across a problem whereby PDO or mysql seems to convert a string to an integer when in an array. Does anyone know why?

If my query is as follows:

$check = $db->prepare("SELECT * FROM tbl_test WHERE id=:id");
$check->execute(array(':id'=>1));

it retrieves 1 record - all fine, but if the query uses a string either by design or mistake as follows:

$check = $db->prepare("SELECT * FROM tbl_test WHERE id=:id");
$check->execute(array(':id'=>'1 OR id > 0'));

it still retrieves a record with id=1.

Surely nothing should be found? I appreciate I should never allow the 2nd scenario to happen but why is PDO / mysql converting the string to an integer and how is it doing it?

Upvotes: 3

Views: 1578

Answers (4)

bobflux
bobflux

Reputation: 11581

This is a MySQL bug/oversight in string to integer conversion. Instead of raising an error when given an incorrect integer literal, it simply issues a warning.

mysql> select '1'+0;
+-------+
| '1'+0 |
+-------+
|     1 |
+-------+
1 row in set (0,00 sec)

mysql> select '1 hello world'+0;
+-------------------+
| '1 hello world'+0 |
+-------------------+
|                 1 |
+-------------------+
1 row in set, 1 warning (0,00 sec)

mysql> show warnings;
+---------+------+---------------------------------------------------+
| Level   | Code | Message                                           |
+---------+------+---------------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: '1 hello world' |
+---------+------+---------------------------------------------------+
1 row in set (0,00 sec)

Upvotes: 4

Lorna Mitchell
Lorna Mitchell

Reputation: 1986

With prepared statements and placeholders, the database knows to expect a value that suits the column type. I would expect that it sees your numeric id column and casts the '1 or id > 0' to a number - so you just get the 1.

Upvotes: 0

Álvaro González
Álvaro González

Reputation: 146410

For good or bad, that's how MySQL is designed to behave:

mysql> SELECT CASE
    -> WHEN 123='123 pink elephants' THEN 'Equal'
    -> ELSE 'Different' END
    -> AS 'How are they?';
+---------------+
| How are they? |
+---------------+
| Equal         |
+---------------+
1 row in set, 1 warning (0.00 sec)

As you can see, though, it triggers a warning:

mysql> SHOW WARNINGS;
+---------+------+--------------------------------------------------------+
| Level   | Code | Message                                                |
+---------+------+--------------------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: '123 pink elephants' |
+---------+------+--------------------------------------------------------+
1 row in set (0.00 sec)

Upvotes: 3

ponury-kostek
ponury-kostek

Reputation: 8060

It's because execute create somthing like: SELECT * FROM tbl_test WHERE id='1 OR id > 0'

$check = $db->prepare("SELECT * FROM tbl_test WHERE id=:id OR id>:id2");
$check->execute(array(':id'=>'1', ':id2' => 0));

or just

$check = $db->prepare("SELECT * FROM tbl_test WHERE id>:id");
$check->execute(array(':id'=>'0'));

Upvotes: 0

Related Questions