phpClickHouse icon indicating copy to clipboard operation
phpClickHouse copied to clipboard

Support for generator.

Open Legion112 opened this issue 3 years ago • 5 comments

Instead of loading all item in mermory ->rows or using the readSteam function would be nice to have a iterator interface to be able to loop all items without loading them to memory.

Something like:

$client->select('SELECT * FORM table');
foreach($client->interator() as $row) {
    echo $row['first_column] . ',' . $row['second_column];
}

Legion112 avatar Jun 08 '22 12:06 Legion112

Add

// Statement Iterator
$state=$this->client->select('SELECT (number+1) as nnums FROM system.numbers LIMIT 5');
foreach ($state as $key=>$value) {
    echo $value['nnums'];
}

isublimity avatar Jun 09 '22 18:06 isublimity

Could you explain how this gonna work in detail will it use chunking to load only a few record into application memory? How to configure the size of chunk?

Legion112 avatar Jun 10 '22 06:06 Legion112

I have quite the same issue @Legion112 , did you find a clean solution ? I seems the right way is to use a streamReader but I can't find a simple way to process each record properly without going into complex stream buffering stuff. Would there be a simple way to achieve that @isublimity ?

Thanks !

ahfeel avatar Feb 20 '23 11:02 ahfeel

Hm.. I haven't finished that feature in my application. (We cancel the creation of features which require this API) I guess this has to be part of this library interface. The library should handle all the pagination logic or the use of pointers.

Legion112 avatar Feb 20 '23 14:02 Legion112

Thanks for your feedback @Legion112 :) Here's a quick class I've written to make the job easier (we use JSON format, so your QUERY must have FORMAT JSONEachRow):

<?php

class JsonRowStreamReader extends \ClickHouseDB\Transport\StreamRead
{
    private $stream;
    private $objectCallback;

    public function __construct()
    {
        $this->stream = fopen('php://memory','r+');

        parent::__construct($this->stream);

        parent::closure(function($ch, $packet) {
            static $temporaryChunk = '';

            $len = strlen($packet);
            $last_char = $packet[$len - 1];
            $lines = explode("\n", $temporaryChunk . $packet);

            if ($last_char == "\n") {
                array_pop($lines);
                $temporaryChunk = '';
            } else {
                $temporaryChunk = array_pop($lines);
            }

            foreach ($lines as $row) {
                $object = json_decode($row, true);
                if (isset($this->objectCallback) && is_callable($this->objectCallback)) {
                    call_user_func($this->objectCallback, [$object]);
                }
            }

            return $len;
        });
    }

    public function closure(callable $callable)
    {
        $this->objectCallback = $callable;
    }
}

ahfeel avatar Feb 20 '23 16:02 ahfeel