PDO一般错误(HY000)时nextRowSet一个语句CALLing程序

时间:2016-06-08 08:22:58

标签: php mysql stored-procedures pdo

我在MySQL中有一个存储例程来执行SELECT 并调用另一个assert子例程(即使不调用assert也会出现同样的问题甚至使用SELECT null;代替以下代码:

CREATE PROCEDURE `account_login`(IN `email` VARCHAR(50), IN `password` VARCHAR(200))
    LANGUAGE SQL
    NOT DETERMINISTIC
    READS SQL DATA
    SQL SECURITY INVOKER
    COMMENT ''
BEGIN

    SELECT SQL_CALC_FOUND_ROWS a.id AS id
        FROM account AS a
        WHERE a.email = email AND password_hash(password, a.password_salt) = a.password_hash
    ;

    CALL assert((SELECT FOUND_ROWS()) = 1, 'WrongLoginCredentials', 'Bad login or bad password');

END$$

如果断言为assert,则throw调用另一个FALSE例程。

CREATE PROCEDURE `assert`(
        IN `assertion` BOOLEAN,
        IN exceptionClass TINYTEXT,
        IN errorMessage TEXT)
    LANGUAGE SQL
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY INVOKER
    COMMENT ''
BEGIN

    IF NOT(`assertion`) THEN
        CALL throw(exceptionClass, errorMessage);
    END IF;

END$$
如果断言失败,

throw会调用SIGNAL 45000

CREATE PROCEDURE `throw`(
        IN exceptionClass TINYTEXT,
        IN errorMessage TEXT)
    LANGUAGE SQL
    NOT DETERMINISTIC
    READS SQL DATA
    SQL SECURITY INVOKER
    COMMENT ''
BEGIN

    ROLLBACK;
    SELECT 1 AS exception, errorMessage as message, 42 AS code, exceptionClass as class;

    SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT=errorMessage,
        MYSQL_ERRNO=42,
        CLASS_ORIGIN=exceptionClass;

END$$

如果我使用假凭证在HeidiSQL中调用此过程,则会发出信号。如果我使用正确的凭据在HeidiSQL中调用它,它将返回结果集(SELECT过程中的account_login)。

但是当我使用PDO编写的语句在PHP中调用它时:

        $this->pdo = new PDO($this->dbDsn, '...', '...', array(
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
        ));

        $loginRequest = $this->pdo->prepare('CALL account_login(?, ?)');
        $loginRequest->execute(array($email, $password));

        $loginRequest->debugDumpParams();
        do {
            $resultSets[] = $loginRequest->fetchAll();
        } while ($loginRequest->nextRowset());

        $loginRequest->closeCursor();

然后我得到错误凭据的预期异常(因为SIGNAL,罚款)和意外的GENERAL ERROR,以获得第二次调用fetchAll时提出的正确凭据。

同样的问题出现在throw(没有SELECT或没有SIGNAL的情况下,或者在调用同一个PDO GENERAL ERROR时没有任何结果account_login具有正确的凭据)。

未准备好的陈述$this->pdo->query('CALL account_login($..., $...);

也是如此

这在PHP 5.3中通过Apache发生,但也通过CLI在PHP 5.6中发生。

那里有什么问题?

0 个答案:

没有答案