3

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?

4 Answers 4

4

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)
Sign up to request clarification or add additional context in comments.

5 Comments

Many thanks. Interestingly even if I bind a parameter and use 'PDO::PARAM_INT' it makes no difference - just issues a warning.
I was quite surprised to find bindParam doesn't throw an Exception when you attempt to bind a string with PDO::PARAM_INT as well... seems it follows PHPs general String > Int conversion rules.
... actually bindParam doesn't even do what I thought: stackoverflow.com/questions/833510/… (did some further digging and deleted my incorrect answer when it was pointed out) @user2875878
Weeelll... it's PHP. Anyone expecting PHP to do the right thing with types is on drugs...
@peufeu However, in this precise situation it behaves exactly as MySQL does (demo) and it isn't more insane than JavaScript (demo).
3

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)

Comments

0

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'));

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.