PDO y PHP/MySQL: ¿qué diablos está mal con las declaraciones preparadas de PDO?

Sé que el título suena ridículo, pero he investigado durante horas solo para darme cuenta de que, en última instancia, PDO tiene errores y no tiene una solución obvia ... Estoy dedicado a estar abierto para uno. También estoy dispuesto a aceptar que mi código es defectuoso.

Usando PHP 5.2/Ubuntu, este código funciona (sin usar declaraciones preparadas/abierto a inyección):

$sql ="SELECT COUNT(*) FROM property p
INNER JOIN property_attribute pa ON p.property_id = pa.property_id
INNER JOIN property_area pc ON p.property_id = pc.property_id
WHERE pa.attribute_value_id
    IN (
        SELECT av.attribute_value_id
        FROM attribute_value av
        INNER JOIN attribute a ON av.attribute_id = a.attribute_id
        WHERE a.name LIKE '$attributes'
        AND av.value LIKE '$values'
    ) 
ORDER BY p.price ASC";
$params = array();
$rHowManyPages = Listings::HowManyPages($sql, $params);

Sin embargo, usando las maravillosas declaraciones preparadas de PDO:

$sql ='SELECT COUNT(*) FROM property p
INNER JOIN property_attribute pa ON p.property_id = pa.property_id
INNER JOIN property_area pc ON p.property_id = pc.property_id
WHERE pa.attribute_value_id
    IN (
        SELECT av.attribute_value_id
        FROM attribute_value av
        INNER JOIN attribute a ON av.attribute_id = a.attribute_id
        WHERE a.name LIKE :attributes
        AND av.value LIKE :values
    ) 
ORDER BY p.price ASC';
$params = array(':attributes' => $attributes, ':values' => $values);
$rHowManyPages = Listings::HowManyPages($sql, $params);

Funciona, un poco. Aquí está la parte de la locura espartana: 1 de cada 5 actualizaciones de los mismos datos que se pasan, PDO da este error:

TEXT: SQLSTATE[HY093]: Invalid parameter number

¡Es al azar! ¿Como y por qué?

preguntado el 27 de julio de 12 a las 23:07

1 Respuestas

¿Es posible que uno de los valores proporcionados para los argumentos nombrados contenga un signo de interrogación? Me encontré con un problema con eso, pero eso fue hace mucho tiempo. (Ciertamente espero que ya lo hayan arreglado).

En mi experiencia limitada, el soporte de PDO para "argumentos con nombre" es algo incompleto.

Por un lado, no puede usar el mismo argumento con nombre en varios lugares de una declaración, el nombre del marcador de posición para cada argumento con nombre debe ser único y solo se puede usar una vez. Y eso hace desaparecer uno de los grandes beneficios de los argumentos con nombre.

Creo que el problema que encontré con el carácter de signo de interrogación en un valor, y la incapacidad de hacer referencia a un argumento con nombre más de una vez (no lo he confirmado) se debe a que el soporte de "argumento con nombre" de PDO es una idea de último momento al apoyo de argumentos posicionales; esencialmente, parece que los "argumentos con nombre" se traducen en argumentos posicionales.

También encontré algunas dudas cuando los argumentos nombrados incluían caracteres de subrayado.

Mi solución fue (¡ACCCKKK!) Usar argumentos posicionales en lugar de argumentos con nombre.

(Por mucho que deteste usar argumentos posicionales, funcionó para mí).

(No veo nada malo en el código que muestra que explicaría el comportamiento observado. Obviamente, hay otro código que no está mostrando).

Además, es posible que desee verificar que su $params array contiene solo los dos elementos; Recibí el mismo mensaje de error cuando mi matriz tenía un elemento "extra" no coincidente. Por otra parte, en mi código, volví a usar solo escalares y vinculé cada uno por separado, en lugar de que PDO lo estropee. (No fue un problema para mí, ese es el patrón con el que estoy demasiado familiarizado en Perl DBI. En lugar de ensuciar la depuración de los problemas, trabajé alrededor de ellos).


NOTA: Por argumentos posicionales, me refiero a usar un signo de interrogación en lugar de un nombre:

 $sql = " ...
  WHERE a.name LIKE ?
    AND av.value LIKE ?
 ... ";

$sth->bindParam(1, $attributes);
$sth->bindParam(2, $values);

Respondido 27 Jul 12, 23:07

Este error de Drupal muestra un problema similar si sus valores tienen : en ellos. - Brendan largo

@Brendan: excelente punto, definitivamente puedo ver cómo un carácter de dos puntos en los datos de enlace podría generar un problema similar al que experimenté con el carácter de signo de interrogación. - spencer7593

@ spencer7593 una respuesta excepcional. No estoy seguro de cómo hacer que funcione en mi caso sin mucha refactorización (tengo una clase que hace todas mis preparaciones y ejecuciones de DBO), pero esto ciertamente responde mucho. Gracias. - brandon minton

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