Después de obtener todos los resultados en su ciclo de ejecución, debe obtener el siguiente conjunto de filas y luego cerrar el cursor antes de intentar ejecutar el procedimiento almacenado nuevamente. Prueba esto:
foreach($data_arr AS $key => $val){
$values = $val;
$stmt->execute();
$res = $stmt->fetchAll();
$stmt->nextRowset(); // NEW: Get the next rowset after fetching your results
$stmt->closeCursor(); // NEW: Close the cursor
}
La adición realmente importante aquí es la llamada a nextRowSet() . Debajo del capó, PDO está devolviendo un segundo rowset al que debe acceder antes de ejecutar un segundo (y posterior) procedimiento almacenado en la misma conexión.