PDO: diferencia entre parámetros de enlace y cadena de concatenación

I have this weird problem. Why do these two implementations return different results?

    $db = DbBase::getInstance();
    $stmt = $db->prepare('SELECT round(round(9.50 * :amount, 2) * 23 * 0.01, 2)');
    $stmt->execute(array(':amount' => 1));
    echo $stmt->fetchColumn();

    Result: 2.18

    $db = DbBase::getInstance();
    $stmt = $db->prepare('SELECT round(round(9.50 * 1, 2) * 23 * 0.01, 2)');
    $stmt->execute();
    echo $stmt->fetchColumn();

    Result: 2.19

When I bind the amount it gives me different result. I'd rather not concatenate the string because of the SQL injections.

preguntado el 28 de agosto de 12 a las 09:08

What's "behind" $db? A sqlite, MySQL, postgresql, ??? connection? -

MySQL and it is a wrapper for PDO. -

1 Respuestas

When you are using the array to pass the data, the data is passed as a string:

Desde el documentos:

Una matriz de valores con tantos elementos como parámetros vinculados en la instrucción SQL que se está ejecutando. Todos los valores se tratan como PDO::PARAM_STR.

However, when you are manually entering in the 1 into the query directly it is being treated as an int. Let me see if I can do some further digging to see what happens internally when a string is converted into an int for you.

Edit: This is probably one of the most similar bugs that have been submitted and accepted:

1)
SET @a = 1;
SELECT @a;

2)
SET @a = 1.1;
SELECT @a;

.. and this 

3)
SET @a = 1.1;
SELECT @a + 7;
returns '8.100000000000000000000000000000'
(probably the addition will convert "1.1" to a double, the result 
of the addition is also a DOUBLE and finally the DOUBLE is converted 
to a string - that should be OK as well as far as I can understand)

So it looks like internally mysql is converting to a double when you pass it an int. That would explain rather nicely the behavior that you are seeing.

Here is a list of other similar (numbers not quite right) bugs you might be interested in:

http://bugs.mysql.com/bug.php?id=46037

http://bugs.mysql.com/bug.php?id=35071

http://bugs.mysql.com/bug.php?id=35071 <-- Good one showing difference between Win and Lin

Y un filtered list of data type bugs that I perused which make for interesting reading.

Edit 2: Aha!

Aquí hay una bug that rather perfectly explains your issue:

Reproduce code:
---------------
CREATE TABLE my_db.my_table (
  id int(10) unsigned NOT NULL auto_increment,
  PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

<?php
$DB = new PDO('mysql:dbname=my_db;host=localhost', 'user', 'pass');
$stmt = $DB->prepare('select * from my_table where id>?');
$stmt->bindValue(1, 13);
$stmt->execute();
?>

or

<?php
$DB = new PDO('mysql:dbname=my_db;host=localhost', 'user', 'pass');
$stmt = $DB->prepare('select * from my_table where id>?');
$stmt->execute(array(13));
?>

Expected result:
----------------
select * from my_table where id>13

Actual result:
--------------
select * from my_table where id>'13'

Respondido 28 ago 12, 10:08

+1 for "Let me see if I can do some further digging to see what happens internally when a string is converted into an int for you." WAITING :) - intercambiar

@swapnesh Yeah, I love to find out how things work on the inside with these sorts of gems :) - Fluffeh

Well I have to correct my question. Actually I want to bind float values and I couldnt find a way to do it. - PPPHP

@PPPHP That might change things quite a bit then (for the worse for you) Floats will be even menos accurate when you pass them through. Can you not get away with decimals in your database instead? - Fluffeh

@swapnesh All good, I don't answer here just to get rep. I love to learn these things - and what better way than to dig into problems that interest me just as much as the OP :) Having found the details for this bug, I will be able to deal with it better in my own code moving forward. - Fluffeh

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.