sql >> データベース >  >> RDS >> PostgreSQL

バインドされていないパラメーター(およびクエリに変数がない)でPDOが例外をスローしない

    この動作は現在のPHP(5.6.13)で再現可能であり、クエリはサーバーに送信されません。

    あなたのケースはドキュメント で説明されています として:

    0の値が期待され、1の値が指定され、ステートメントは失敗します、false 返されます。これまでのところ、文書化されているとおりに機能します。

    エラーが発生しました」と主張するかもしれません。 "は、ERRMODE_EXCEPTION オンの場合、例外がスローされます。それは議論ですが、PDO開発者がそれに同意するかどうかは明らかではありません。

    更新:

    SQLCodeが選ばれる理由 設定されていませんか?

    PDOソースコード、具体的にはstatic PHP_METHOD(PDOStatement, execute)を見てください。 PDO ::execute()を処理する場合、すべてのエラーがマクロによって処理されることがわかります: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); }
    

    重要なのは、PDOが何も期待していないときにバインドされたパラメーターを渡すと、クエリがSQLエンジンに到達しないため、SQLエンジンがSQLSTATEに伴うエラーを報告する機会がないということです。

    PDO自体は偽のSQLSTATEを作成しません それ自体では、少なくともその場合はそうではないので、stmt->error_code PDO_ERR_NONEにとどまります これは"00000"です 。

    例外を発生させたいことは理解できますが、 https://bugs.phpに提案する必要があります。ネット

    MySQLと同じですか?

    はい、ルートの動作は同じですが、MySQLドライバーではprepare はすぐにSQLエンジンに送信されるため、列が不良であるために正しくない場合は、早期に失敗し、実際のSQLエラーが発生します。一方、PgSQLドライバーには、サーバー側のprepareを延期する別の実装があります。 。この特定の動作については、 PHP Postgres PDOドライバーがプリペアドステートメントをサポートしていませんか? で詳しく説明されています。

    とにかく、これが私の説明を示すMySQLのケースです。つまり:

    • クエリは0個のパラメータを想定しており、1個が指定されています
    • $stmt->execute falseを返します
    • 例外は発生しません
    • PDO::errorCodeは00000です

    コード:

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

    結果:

    内部で何が起こるかというと、prepare サーバーに送信されて成功しますが、execute パラメータの不一致により、ステップはPDOによってキャンセルされます。

    これは、クエリが存在しない列を参照しているという事実が異なる場合です。 $stmt->executeであることを示す印刷を追加しています $stmt->prepareによって例外が発生するため、は呼び出されません。

    コード:

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

    結果:

    prepareであるため、「Executingquery」ステップが発生しないことに注意してください。 それは失敗します、サーバー側。

    結論

    • クエリがサーバーに送信されると、prepare()またはexecute()のどちらでも、エラーを生成するのはサーバーであるため、PDOExceptionが発生することが予想されます。

    • クエリが実行ステップのためにサーバーに送信されない場合、PDO execute()は失敗する可能性があります(falseを返します)が、例外はスローされず、errorCode() 00000にとどまります



    1. エラー!サーバーはPIDファイル(/usr/local/var/mysql/`username`.lan.pid)を更新せずに終了します

    2. データベースPerlへの接続

    3. VB.netのOracle日時

    4. mysql-文字列を連結し、文字列を日付に変換する方法は?