public function rows($format = self::RETURN_ASSOCIATIVE)
    {
        $bufferedResults = [];
        $call = $this->call;
        $generator = null;
        $shouldRetry = false;
        $backoff = new ExponentialBackoff($this->retries, function ($ex) {
            if ($ex instanceof ServiceException) {
                return $ex->getCode() === Grpc\STATUS_UNAVAILABLE;
            }

            return false;
        });

        $valid = $backoff->execute(function () use ($call, &$generator) {
            $generator = $call();
            return $generator->valid();
        });

        while ($valid) {
            try {
                $result = $generator->current();
                $bufferedResults[] = $result;
                $this->setResultData($result, $format);

                $empty = false;
                if (!isset($result['values']) || $this->columnCount === 0) {
                    $empty = true;
                }

                $hasResumeToken = $this->isSetAndTrue($result, 'resumeToken');
                if ($hasResumeToken || count($bufferedResults) >= self::BUFFER_RESULT_LIMIT) {
                    $chunkedResult = null;
                    if (!$empty) {
                        list($yieldableRows, $chunkedResult) = $this->parseRowsFromBufferedResults($bufferedResults);

                        foreach ($yieldableRows as $row) {
                            yield $this->mapper->decodeValues($this->columns, $row, $format);
                        }
                    }

                    // Now that we've yielded all available rows, flush the buffer.
                    $bufferedResults = [];
                    $shouldRetry = $hasResumeToken;

                    // If the last item in the buffer had a chunked value let's
                    // hold on to it so we can stitch it together into a yieldable
                    // result.
                    if ($chunkedResult) {
                        $bufferedResults[] = $chunkedResult;
                    }
                }

                $generator->next();
                $valid = $generator->valid();
            } catch (ServiceException $ex) {
                if ($shouldRetry && $ex->getCode() === Grpc\STATUS_UNAVAILABLE) {
                    // Attempt to resume using our last stored resume token. If we
                    // successfully resume, flush the buffer.
                    $generator = $backoff->execute($call, [$this->resumeToken]);
                    $bufferedResults = [];

                    continue;
                }

                throw $ex;
            }
        }

        // If there are any results remaining in the buffer, yield them.
        if ($bufferedResults) {
            list($yieldableRows, $chunkedResult) = $this->parseRowsFromBufferedResults($bufferedResults);

            foreach ($yieldableRows as $row) {
                yield $this->mapper->decodeValues($this->columns, $row, $format);
            }
        }
    }