sql >> Base de Datos >  >> RDS >> PostgreSQL

PDO no arroja una excepción con parámetros no vinculados (y sin variables en la consulta)

Ese comportamiento es reproducible con el PHP actual (5.6.13) y la consulta ni siquiera se envía al servidor.

Su caso se describe en el documento como:

Se espera un valor de 0, se da un valor de 1 y la declaración falla, false siendo devuelto. Hasta ahora, funciona según lo documentado.

Puede argumentar que "se emite un error " implicaría que cuando ERRMODE_EXCEPTION está activado, se lanzará una excepción. Ese es un argumento, pero no es obvio que los desarrolladores de PDO estarían de acuerdo con él.

Actualización:

¿Por qué SQLCode no configurado?

Mirando el código fuente de PDO, específicamente static PHP_METHOD(PDOStatement, execute) que maneja PDO::execute(), puede ver que todos los errores son manejados por una macro:PDO_HANDLE_STMT_ERR()

#define PDO_HANDLE_STMT_ERR()   if (strcmp(stmt->error_code, PDO_ERR_NONE)) { pdo_handle_error(stmt->dbh, stmt TSRMLS_CC); }

El punto es que, al pasar un parámetro vinculado cuando PDO no esperaba ninguno, la consulta nunca llega al motor SQL, por lo que el motor SQL nunca tiene la oportunidad de informar un error acompañado de un SQLSTATE

PDO en sí mismo no crea un SQLSTATE falso por sí solo, al menos no en ese caso, entonces stmt->error_code permanece en PDO_ERR_NONE que es "00000" .

Es comprensible que prefiera que se genere una excepción, pero entonces debería sugerirlo a https://bugs.php. red

¿Es lo mismo con MySQL?

Sí, el comportamiento de root es el mismo excepto que con el controlador MySQL, el prepare se envía inmediatamente al motor de SQL, por lo que si es incorrecto debido a una columna incorrecta, falla antes y con un error de SQL real. Por otro lado, el controlador PgSQL tiene una implementación diferente que lo hace aplazar el prepare del lado del servidor . Este comportamiento particular se analiza en detalle en ¿El controlador PHP Postgres PDO no es compatible con declaraciones preparadas?

De todos modos, aquí hay un caso con MySQL que demuestra mi explicación, es decir:

  • la consulta espera 0 parámetros, se da 1
  • $stmt->execute devuelve falso
  • no se genera ninguna excepción
  • PDO::errorCode es 00000

Código:

$link = new PDO('mysql:dbname=' . $name . ';host=' . $host, $user, $password);
$link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {
    $stmt = $link->prepare("SELECT 1");
    $rc=$stmt->execute(array(1));
   if ($rc===false)
    echo "query failed, errorCode=", $link->errorCode(), "\n";
   else
    echo "query succeeded, errorCode=", $link->errorCode(), "\n";
}
catch (PDOException $e) {
    print "A PDOException has occurred";
    print $e->getMessage();
}

Resultado:

Lo que sucede debajo del capó es que el prepare se envía al servidor y tiene éxito, pero el execute el paso es cancelado por PDO debido a la falta de coincidencia en los parámetros.

Aquí hay un caso que difiere en el hecho de que la consulta se refiere a una columna que no existe. Estoy agregando una impresión para mostrar que $stmt->execute ni siquiera se llama, ya que la excepción la genera $stmt->prepare

Código:

$link = new PDO('mysql:dbname=' . $name . ';host=' . $host, $user, $password);
$link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {
    $stmt = $link->prepare("SELECT nonexisting");
    echo "Executing query\n";
    $rc=$stmt->execute(array(1));
   if ($rc===false)
    echo "query failed, errorCode=", $link->errorCode(), "\n";
   else
    echo "query succeeded, errorCode=", $link->errorCode(), "\n";
}
catch (PDOException $e) {
  print "A PDOException has occurred";
    print $e->getMessage();
}

Resultado:

Tenga en cuenta que el paso "Ejecutar consulta" nunca ocurre, porque es el prepare eso falla, del lado del servidor.

Conclusión

  • cuando la consulta se envía al servidor, ya sea en preparar() o ejecutar(), y es el servidor el que genera un error, podemos esperar que se genere una excepción PDO.

  • cuando la consulta no se envía al servidor para un paso de ejecución, entonces la ejecución de PDO () puede fallar (devuelve falso) pero no se lanza ninguna excepción y errorCode() permanece en 00000