PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

PDO ne levant pas d'exception avec des paramètres non liés (et aucune variable dans la requête)

Ce comportement est reproductible avec le PHP actuel (5.6.13), et la requête n'est même pas envoyée au serveur.

Votre cas est décrit dans la doc comme :

0 valeur est attendue, 1 valeur est donnée et l'instruction échoue, false étant retourné. Jusqu'à présent, fonctionne comme documenté.

Vous pouvez argumenter que "une erreur est émise " impliquerait que lorsque ERRMODE_EXCEPTION est activé, une exception serait levée. C'est un argument, mais il n'est pas évident que les développeurs de PDO seraient d'accord.

Mise à jour :

Pourquoi SQLCode pas défini ?

En regardant le code source PDO, en particulier static PHP_METHOD(PDOStatement, execute) qui gère PDO::execute(), vous pouvez voir que toutes les erreurs sont gérées par une 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); }

Le fait est que, lors du passage d'un paramètre lié alors que PDO n'en attendait aucun, la requête n'arrive jamais au moteur SQL, de sorte que le moteur SQL n'a jamais la possibilité de signaler une erreur accompagnée d'un SQLSTATE

PDO lui-même ne crée pas un faux SQLSTATE tout seul, du moins non dans ce cas, doncstmt->error_code reste à PDO_ERR_NONE qui est "00000" .

Il est compréhensible que vous préfériez qu'une exception soit déclenchée, mais vous devriez alors le suggérer à https://bugs.php. net

Est-ce la même chose avec MySQL ?

Oui, le comportement root est le même sauf qu'avec le pilote MySQL, le prepare est envoyé immédiatement au moteur SQL donc s'il est incorrect à cause d'une mauvaise colonne, il échoue plus tôt et avec une vraie erreur SQL. D'autre part, le pilote PgSQL a une implémentation différente qui lui fait différer la prepare côté serveur . Ce comportement particulier est discuté en détail sur Le pilote PHP Postgres PDO ne prend pas en charge l'instruction préparée ?

Quoi qu'il en soit, voici un cas avec MySQL qui démontre mon explication, c'est-à-dire :

  • la requête attend 0 paramètre, 1 est donné
  • $stmt->execute renvoie faux
  • aucune exception n'est déclenchée
  • PDO::errorCode est 00000

Code :

$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();
}

Résultat :

Ce qui se passe sous le capot, c'est que le prepare est envoyé au serveur et réussit, mais le execute l'étape est annulée par PDO en raison de la non-concordance des paramètres.

Voici un cas qui diffère par le fait que la requête fait référence à une colonne inexistante. J'ajoute une impression pour montrer que $stmt->execute n'est même pas appelé, car l'exception est levée par $stmt->prepare

Code :

$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();
}

Résultat :

Notez que l'étape "Exécution de la requête" ne se produit jamais, car il s'agit de la prepare qui échoue, côté serveur.

Conclusion

  • lorsque la requête est envoyée au serveur, que ce soit dans prepare() ou execute(), et que c'est le serveur qui génère une erreur, alors nous pouvons nous attendre à ce qu'une PDOException soit levée.

  • lorsque la requête n'est pas envoyée au serveur pour une étape d'exécution, alors PDO execute() peut échouer (retourne false) mais aucune exception n'est levée et errorCode() reste à 00000