Question

First the guilty code:

$preparedGetData = $db->prepare("CALL getData(?)");
foreach($userSet as $r) {
    $preparedGetData->execute(array($r['id_user']));
    $rs = $preparedGetData->fetchAll();
    $preparedGetData->closeCursor();
}

Explication

getData = stored procedure in mysql
$db = instance of Zend_Db_Adapter_Pdo_Mysql (using Zend version 1.10.0 )

Symptoms

  • When I leave out closeCursor in the second cycle I already get error:

    PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.

  • But I am using fetchAll !!!

  • When I add the closeCursor the result arrives incomplete. Invoking CALL getData('3872') in query browser returns 1 row with 72 columns. The same done by the code above returns 1 row with only first 41 columns.

What I'm doing wrong?

Edit2: Semi-solution

Code updated to:

$preparedGetData = $db->prepare("CALL getData(?)");
foreach($userSet as $r) {
    $preparedGetData->execute(array($r['id_user']));

    $rs=array();

    do {
        try {
            $partial_rowset = $preparedGetData->fetchAll(); // When I put fetchAll() after the end of the cycle, I get empty resultset.
        } catch (PDOException $error) { // The PDOException doesn't get caught here. Why?
            error_log($error);
        } catch (Exception $error) { 
            error_log($error);
        }
        if ($partial_rowset) {
            $rs=array_merge($rs,$partial_rowset);
        }
    } while ($preparedGetData->nextRowset());
}

Symptoms

  • Getting error:
    PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error
    Next exception 'Zend_Db_Statement_Exception' with message 'SQLSTATE[HY000]: General error' in /home/GIT/includes/Zend/Db/Statement/Pdo.php:294
    on the line with fetchAll.
  • This error I can catch using generic exception.
  • With this code I get all 72 columns.
  • I perceive this nasty because I am deliberately catching generic exception and just turning it into log. Which I guess will also become an performance issue (the cycle runs about 10 000 times).
Was it helpful?

Solution

MySQL stored procedures may have multiple result sets. That is, you can run more than one SELECT query inside a stored procedure, and then iterate over these multiple result sets.

This complicates fetching because the whole result is really like an array of arrays of arrays (multiple result sets, each result set may have multiple rows, each row may have multiple columns).

But fetchAll() only fetches all the rows from one result set. So when you call a stored procedure, you need to force it to flush all result sets. That is, keep calling nextRowset() until that function returns null.

The Zend_Db API is modeled off of PDO, so you can see example usage of nextRowset() in the docs for PDOStatement::nextRowset().

Unfortunately, there is no such function like fetchAllRowsets(). You are left to do it yourself as a while loop.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top