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 eerrorCode()
permanece em00000