PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

PDO não lança exceção com parâmetros não vinculados (e sem variáveis ​​na consulta)


Esse comportamento é reproduzível com o PHP atual (5.6.13), e a consulta nem é enviada ao servidor.

Seu caso está descrito no documento Como:

0 valor é esperado, 1 valor é fornecido e a instrução falha, false sendo devolvido. Até agora, funciona conforme documentado.

Você pode argumentar que "um erro foi emitido " implicaria que quando ERRMODE_EXCEPTION estiver ativado, uma exceção seria lançada. Isso é um argumento, mas não é óbvio que os desenvolvedores do PDO concordem com isso.

Atualizar:

Por que é SQLCode não definido?

Olhando para o código-fonte do PDO, especificamente static PHP_METHOD(PDOStatement, execute) que lida com PDO::execute(), você pode ver que todos os erros são tratados por uma 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); }

O ponto é que, ao passar um parâmetro vinculado quando o PDO não esperava nenhum, a consulta nunca chega ao mecanismo SQL, portanto, o mecanismo SQL nunca tem a oportunidade de relatar um erro acompanhado de um SQLSTATE

O próprio PDO não cria um SQLSTATE falso por conta própria, pelo menos não nesse caso, então stmt->error_code permanece em PDO_ERR_NONE que é "00000" .

É compreensível que você prefira que uma exceção seja levantada, mas então você deve sugerir isso para https://bugs.php. líquido

É o mesmo com o MySQL?

Sim, o comportamento do root é o mesmo, exceto que com o driver MySQL, o prepare é enviado imediatamente para o mecanismo SQL, portanto, se estiver incorreto devido a uma coluna incorreta, ele falhará mais cedo e com um erro SQL real. Por outro lado, o driver PgSQL tem uma implementação diferente que o faz adiar o prepare do lado do servidor . Esse comportamento específico é discutido em detalhes em O driver PHP Postgres PDO não suporta declaração preparada?

De qualquer forma, aqui está um caso com o MySQL que demonstra minha explicação, ou seja:
  • a consulta espera 0 parâmetro, 1 é fornecido
  • $stmt->execute retorna falso
  • nenhuma exceção é gerada
  • PDO::errorCode é 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:

O que acontece nos bastidores é que o prepare é enviado para o servidor e é bem-sucedido, mas o execute etapa é cancelada pelo PDO devido à incompatibilidade nos parâmetros.

Aqui está um caso que difere no fato de que a consulta se refere a uma coluna inexistente. Estou adicionando um print para mostrar que $stmt->execute nem é chamado, pois a exceção é gerada por $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:

Observe como a etapa "Executando consulta" nunca acontece, porque é o prepare que falha, do lado do servidor.

Conclusão

  • quando a consulta é enviada ao servidor, seja em prepare() ou execute(), e é o servidor que gera um erro, então podemos esperar que uma PDOException seja levantada.

  • quando a consulta não é enviada ao servidor para uma etapa de execução, o PDO execute() pode falhar (retorna false), mas nenhuma exceção é lançada e errorCode() permanece em 00000