Completed
Pull Request — master (#102)
by Šimon
06:39
created

Client::prepareInsertAssocBulk()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 25
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 5

Importance

Changes 0
Metric Value
eloc 17
dl 0
loc 25
ccs 17
cts 17
cp 1
rs 9.3888
c 0
b 0
f 0
cc 5
nc 3
nop 1
crap 5
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ClickHouseDB;
6
7
use ClickHouseDB\Exception\QueryException;
8
use ClickHouseDB\Query\Degeneration;
9
use ClickHouseDB\Query\Degeneration\Bindings;
10
use ClickHouseDB\Query\Degeneration\Conditions;
11
use ClickHouseDB\Query\WhereInFile;
12
use ClickHouseDB\Query\WriteToFile;
13
use ClickHouseDB\Quote\FormatLine;
14
use ClickHouseDB\Transport\Http;
15
use ClickHouseDB\Transport\Stream;
16
use function array_flip;
0 ignored issues
show
introduced by
Type array_flip is not used in this file.
Loading history...
17
use function array_keys;
18
use function array_rand;
0 ignored issues
show
introduced by
Type array_rand is not used in this file.
Loading history...
19
use function array_values;
20
use function count;
21
use function date;
22
use function implode;
23
use function in_array;
24
use function is_array;
25
use function is_callable;
26
use function is_file;
27
use function is_readable;
28
use function is_string;
29
use function sprintf;
30
use function stripos;
31
use function strtotime;
32
use function trim;
33
34
class Client
35
{
36
    private const DEFAULT_USERNAME  = 'default';
37
    private const DEFAULT_PASSWORD  = '';
38
    private const DEFAULT_PORT      = 8123;
39
    private const DEFAULT_HOST      = '127.0.0.1';
40
    private const DEFAULT_DATABASE  = 'default';
41
    private const SUPPORTED_FORMATS = ['TabSeparated', 'TabSeparatedWithNames', 'CSV', 'CSVWithNames', 'JSONEachRow'];
42
43
    /** @var Http */
44
    private $transport;
45
46
    /** @var string */
47
    private $username;
48
49
    /** @var string */
50
    private $password;
51
52
    /** @var string */
53
    private $host;
54
55
    /** @var int */
56
    private $port;
57
58
    /** @var string */
59
    private $database;
60
61
    /**
62
     * @param mixed[] $connectParams
63
     * @param mixed[] $settings
64
     */
65 63
    public function __construct(array $connectParams, array $settings = [])
66
    {
67 63
        $this->username = $connectParams['username'] ?? self::DEFAULT_USERNAME;
68 63
        $this->password = $connectParams['password'] ?? self::DEFAULT_PASSWORD;
69 63
        $this->port     = (int) ($connectParams['port'] ?? self::DEFAULT_PORT);
70 63
        $this->host     = $connectParams['host'] ?? self::DEFAULT_HOST;
71 63
        $this->database = $connectParams['database'] ?? self::DEFAULT_DATABASE;
72
73 63
        $this->transport = new Http(
74 63
            $this->host,
75 63
            $this->port,
76 63
            $this->username,
77 63
            $this->password,
78 63
            $this->database
79
        );
80
81 63
        $this->transport->addQueryDegeneration(new Bindings());
82
83
        // apply settings to transport class
84 63
        if (! empty($settings)) {
85 1
            $this->getSettings()->apply($settings);
86
        }
87
88 63
        if (isset($connectParams['https'])) {
89
            $this->setHttps($connectParams['https']);
90
        }
91
92 63
        $this->setHttpCompression(true);
93 63
    }
94
95
    /**
96
     * Clear Degeneration processing request [template ]
97
     */
98 1
    public function cleanQueryDegeneration() : void
99
    {
100 1
        $this->transport->cleanQueryDegeneration();
101 1
    }
102
103
    /**
104
     * Degeneration processing
105
     */
106
    public function addQueryDegeneration(Degeneration $degeneration) : void
107
    {
108
        $this->transport->addQueryDegeneration($degeneration);
109
    }
110
111
    /**
112
     * Add Conditions Degeneration to query processing
113
     */
114 1
    public function enableQueryConditions() : void
115
    {
116 1
        $this->transport->addQueryDegeneration(new Conditions());
117 1
    }
118
119 2
    public function setTimeout(float $seconds) : void
120
    {
121 2
        $this->transport->setTimeout($seconds);
122 2
    }
123
124 2
    public function setConnectTimeout(float $seconds) : void
125
    {
126 2
        $this->transport->setConnectTimeout($seconds);
127 2
    }
128
129
    public function getHost() : string
130
    {
131
        return $this->host;
132
    }
133
134
    /**
135
     * Set connection host
136
     */
137
    public function setHost(string $host) : void
138
    {
139
        $this->host = $host;
140
        $this->transport->setHost($host);
141
    }
142
143
    public function getPassword() : string
144
    {
145
        return $this->password;
146
    }
147
148
    public function getPort() : int
149
    {
150
        return $this->port;
151
    }
152
153
    public function getUsername() : string
154
    {
155
        return $this->username;
156
    }
157
158 63
    public function setDatabase(string $database) : self
159
    {
160 63
        $this->database = $database;
161 63
        $this->transport->setDatabase($database);
162
163 63
        return $this;
164
    }
165
166 2
    public function getTransport() : Http
167
    {
168 2
        return $this->transport;
169
    }
170
171
    /**
172
     * @return mixed
173
     */
174
    public function verbose()
175
    {
176
        return $this->transport->setVerbose();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->transport->setVerbose() targeting ClickHouseDB\Transport\Http::setVerbose() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
The call to ClickHouseDB\Transport\Http::setVerbose() has too few arguments starting with flag. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

176
        return $this->transport->/** @scrutinizer ignore-call */ setVerbose();

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
177
    }
178
179 63
    public function getSettings() : Settings
180
    {
181 63
        return $this->transport->getSettings();
182
    }
183
184
    /**
185
     * @return static
186
     */
187 2
    public function useSession(bool $useSessionId = false)
188
    {
189 2
        if (! $this->getSettings()->getSessionId()) {
190 2
            if (! $useSessionId) {
191 2
                $this->getSettings()->makeSessionId();
192
            } else {
193
                $this->getSettings()->session_id($useSessionId);
0 ignored issues
show
Bug introduced by
$useSessionId of type true is incompatible with the type string expected by parameter $session_id of ClickHouseDB\Settings::session_id(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

193
                $this->getSettings()->session_id(/** @scrutinizer ignore-type */ $useSessionId);
Loading history...
194
            }
195
        }
196
197 2
        return $this;
198
    }
199
200
    /**
201
     * @return mixed
202
     */
203 2
    public function getSession()
204
    {
205 2
        return $this->getSettings()->getSessionId();
206
    }
207
208
    /**
209
     * Query CREATE/DROP
210
     *
211
     * @param mixed[] $bindings
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
212
     * @return Statement
213
     */
214 63
    public function write(string $sql, array $bindings = [], bool $exception = true)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::write() does not have return type hint for its return value but it should be possible to add it based on @return annotation "Statement".
Loading history...
215
    {
216 63
        return $this->transport->write($sql, $bindings, $exception);
217
    }
218
219
    /**
220
     * Write to system.query_log
221
     *
222
     * @return static
223
     */
224
    public function enableLogQueries(bool $flag = true)
225
    {
226
        $this->getSettings()->set('log_queries', (int) $flag);
227
228
        return $this;
229
    }
230
231
    /**
232
     * Compress the result if the HTTP client said that it understands data compressed with gzip or deflate
233
     */
234 63
    public function setHttpCompression(bool $enable) : self
235
    {
236 63
        $this->getSettings()->setHttpCompression($enable);
237
238 63
        return $this;
239
    }
240
241
    /**
242
     * Enable / Disable HTTPS
243
     *
244
     * @return static
245
     */
246 1
    public function setHttps(bool $flag)
247
    {
248 1
        $this->transport->setHttps($flag);
249
250 1
        return $this;
251
    }
252
253
    /**
254
     * Read extremes of the result columns. They can be output in JSON-formats.
255
     *
256
     * @return static
257
     */
258 2
    public function enableExtremes(bool $flag = true)
259
    {
260 2
        $this->getSettings()->set('extremes', (int) $flag);
261
262 2
        return $this;
263
    }
264
265
    /**
266
     * Ping server
267
     *
268
     * @return bool
269
     */
270 39
    public function ping()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::ping() does not have return type hint for its return value but it should be possible to add it based on @return annotation "bool".
Loading history...
271
    {
272 39
        return $this->transport->ping();
273
    }
274
275
    /**
276
     * @param mixed[] $bindings
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
277
     * @return Statement
278
     */
279 29
    public function select(
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::select() does not have return type hint for its return value but it should be possible to add it based on @return annotation "Statement".
Loading history...
280
        string $sql,
281
        array $bindings = [],
282
        WhereInFile $whereInFile = null,
0 ignored issues
show
introduced by
Parameter $whereInFile has null default value, but is not marked as nullable.
Loading history...
283
        WriteToFile $writeToFile = null
0 ignored issues
show
introduced by
Parameter $writeToFile has null default value, but is not marked as nullable.
Loading history...
284
    ) {
285 29
        return $this->transport->select($sql, $bindings, $whereInFile, $writeToFile);
286
    }
287
288
    /**
289
     * prepare select
290
     *
291
     * @param mixed[] $bindings
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
292
     * @return Statement
293
     */
294 5
    public function selectAsync(
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::selectAsync() does not have return type hint for its return value but it should be possible to add it based on @return annotation "Statement".
Loading history...
295
        string $sql,
296
        array $bindings = [],
297
        WhereInFile $whereInFile = null,
0 ignored issues
show
introduced by
Parameter $whereInFile has null default value, but is not marked as nullable.
Loading history...
298
        WriteToFile $writeToFile = null
0 ignored issues
show
introduced by
Parameter $writeToFile has null default value, but is not marked as nullable.
Loading history...
299
    ) {
300 5
        return $this->transport->selectAsync($sql, $bindings, $whereInFile, $writeToFile);
301
    }
302
303
    /**
304
     * @return bool
305
     */
306 10
    public function executeAsync()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::executeAsync() does not have return type hint for its return value but it should be possible to add it based on @return annotation "bool".
Loading history...
307
    {
308 10
        return $this->transport->executeAsync();
309
    }
310
311
    /**
312
     * set progressFunction
313
     */
314 1
    public function progressFunction(callable $callback)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::progressFunction() does not have void return type hint.
Loading history...
315
    {
316 1
        if (! is_callable($callback)) {
317
            throw new \InvalidArgumentException('Not is_callable progressFunction');
0 ignored issues
show
introduced by
Class \InvalidArgumentException should not be referenced via a fully qualified name, but via a use statement.
Loading history...
318
        }
319
320 1
        if (! $this->getSettings()->isSet('send_progress_in_http_headers')) {
321 1
            $this->getSettings()->set('send_progress_in_http_headers', 1);
322
        }
323 1
        if (! $this->getSettings()->isSet('http_headers_progress_interval_ms')) {
324 1
            $this->getSettings()->set('http_headers_progress_interval_ms', 100);
325
        }
326
327 1
        $this->transport->setProgressFunction($callback);
328 1
    }
329
330
    /**
331
     * SHOW PROCESSLIST
332
     *
333
     * @return array
0 ignored issues
show
introduced by
@return annotation of method \ClickHouseDB\Client::showProcesslist() does not specify type hint for items of its traversable return value.
Loading history...
334
     */
335
    public function showProcesslist()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::showProcesslist() does not have return type hint for its return value but it should be possible to add it based on @return annotation "array".
Loading history...
336
    {
337
        return $this->select('SHOW PROCESSLIST')->rows();
338
    }
339
340
    /**
341
     * Get the number of simultaneous/Pending requests
342
     *
343
     * @return int
344
     */
345 12
    public function getCountPendingQueue()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::getCountPendingQueue() does not have return type hint for its return value but it should be possible to add it based on @return annotation "int".
Loading history...
346
    {
347 12
        return $this->transport->getCountPendingQueue();
348
    }
349
350
    /**
351
     * @param mixed[][] $values
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
352
     * @param string[]  $columns
353
     * @return Statement
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::insert() has useless @return annotation.
Loading history...
354
     * @throws Exception\TransportException
355
     */
356 9
    public function insert(string $table, array $values, array $columns = []) : Statement
357
    {
358 9
        if (empty($values)) {
359 1
            throw QueryException::cannotInsertEmptyValues();
360
        }
361
362 8
        if (stripos($table, '`') === false && stripos($table, '.') === false) {
363 5
            $table = '`' . $table . '`'; //quote table name for dot names
364
        }
365 8
        $sql = 'INSERT INTO ' . $table;
366
367 8
        if (count($columns) !== 0) {
368 7
            $sql .= ' (`' . implode('`,`', $columns) . '`) ';
369
        }
370
371 8
        $sql .= ' VALUES ';
372
373 8
        foreach ($values as $row) {
374 8
            $sql .= ' (' . FormatLine::Insert($row) . '), ';
375
        }
376 8
        $sql = trim($sql, ', ');
377
378 8
        return $this->transport->write($sql);
379
    }
380
381
    /**
382
     *       * Prepares the values to insert from the associative array.
383
     *       * There may be one or more lines inserted, but then the keys inside the array list must match (including in the sequence)
384
     *       *
385
     *       * @param mixed[] $values - array column_name => value (if we insert one row) or array list column_name => value if we insert many lines
386
     *       * @return mixed[][] - list of arrays - 0 => fields, 1 => list of value arrays for insertion
387
     *       */
388 3
    public function prepareInsertAssocBulk(array $values)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::prepareInsertAssocBulk() does not have @param annotation for its traversable parameter $values.
Loading history...
introduced by
Method \ClickHouseDB\Client::prepareInsertAssocBulk() does not have return type hint nor @return annotation for its return value.
Loading history...
389
    {
390 3
        if (isset($values[0]) && is_array($values[0])) { //случай, когда много строк вставляется
391 2
            $preparedFields = array_keys($values[0]);
392 2
            $preparedValues = [];
393 2
            foreach ($values as $idx => $row) {
394 2
                $_fields = array_keys($row);
395 2
                if ($_fields !== $preparedFields) {
396 1
                    throw new QueryException(
397 1
                        sprintf(
398 1
                            'Fields not match: %s and %s on element %s',
399 1
                            implode(',', $_fields),
400 1
                            implode(',', $preparedFields),
401 1
                            $idx
402
                        )
403
                    );
404
                }
405 2
                $preparedValues[] = array_values($row);
406
            }
407
        } else {
408 1
            $preparedFields = array_keys($values);
409 1
            $preparedValues = [array_values($values)];
410
        }
411
412 2
        return [$preparedFields, $preparedValues];
413
    }
414
415
    /**
416
     * Inserts one or more rows from an associative array.
417
     * If there is a discrepancy between the keys of the value arrays (or their order) - throws an exception.
418
     *
419
     * @param mixed[] $values - array column_name => value (if we insert one row) or array list column_name => value if we insert many lines
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
420
     * @return Statement
421
     */
422
    public function insertAssocBulk(string $tableName, array $values)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::insertAssocBulk() does not have return type hint for its return value but it should be possible to add it based on @return annotation "Statement".
Loading history...
423
    {
424
        list($columns, $vals) = $this->prepareInsertAssocBulk($values);
0 ignored issues
show
introduced by
list(...) is forbidden, use [...] instead.
Loading history...
425
426
        return $this->insert($tableName, $vals, $columns);
427
    }
428
429
    /**
430
     * insert TabSeparated files
431
     *
432
     * @param string|string[] $fileNames
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
433
     * @param string[]        $columns
434
     * @return mixed
435
     */
436 1
    public function insertBatchTSVFiles(string $tableName, $fileNames, array $columns = [])
437
    {
438 1
        return $this->insertBatchFiles($tableName, $fileNames, $columns, 'TabSeparated');
439
    }
440
441
    /**
442
     * insert Batch Files
443
     *
444
     * @param string|string[] $fileNames
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
445
     * @param string[]        $columns
446
     * @param string          $format ['TabSeparated','TabSeparatedWithNames','CSV','CSVWithNames']
0 ignored issues
show
Coding Style introduced by
Expected 4 spaces after parameter name; 1 found
Loading history...
447
     * @return Statement[]
448
     * @throws Exception\TransportException
449
     */
450 8
    public function insertBatchFiles(string $tableName, $fileNames, array $columns = [], string $format = 'CSV')
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::insertBatchFiles() does not have return type hint for its return value but it should be possible to add it based on @return annotation "Statement[]".
Loading history...
451
    {
452 8
        if (is_string($fileNames)) {
453
            $fileNames = [$fileNames];
454
        }
455 8
        if ($this->getCountPendingQueue() > 0) {
456
            throw new QueryException('Queue must be empty, before insertBatch, need executeAsync');
457
        }
458
459 8
        if (! in_array($format, self::SUPPORTED_FORMATS, true)) {
460
            throw new QueryException('Format not support in insertBatchFiles');
461
        }
462
463 8
        $result = [];
464
465 8
        foreach ($fileNames as $fileName) {
466 8
            if (! is_file($fileName) || ! is_readable($fileName)) {
467
                throw  new QueryException('Cant read file: ' . $fileName . ' ' . (is_file($fileName) ? '' : ' is not file'));
468
            }
469
470 8
            if (empty($columns)) {
471
                $sql = 'INSERT INTO ' . $tableName . ' FORMAT ' . $format;
472
            } else {
473 8
                $sql = 'INSERT INTO ' . $tableName . ' ( ' . implode(',', $columns) . ' ) FORMAT ' . $format;
474
            }
475 8
            $result[$fileName] = $this->transport->writeAsyncCSV($sql, $fileName);
476
        }
477
478
        // exec
479 8
        $this->executeAsync();
480
481
        // fetch resutl
482 8
        foreach ($fileNames as $fileName) {
483 8
            if (! $result[$fileName]->isError()) {
484 6
                continue;
485
            }
486
487 2
            $result[$fileName]->error();
488
        }
489
490 6
        return $result;
491
    }
492
493
    /**
494
     * insert Batch Stream
495
     *
496
     * @param string[] $columns
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
497
     * @param string   $format ['TabSeparated','TabSeparatedWithNames','CSV','CSVWithNames']
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 1 found
Loading history...
498
     * @return Transport\CurlerRequest
499
     */
500 2
    public function insertBatchStream(string $tableName, array $columns = [], string $format = 'CSV')
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::insertBatchStream() does not have return type hint for its return value but it should be possible to add it based on @return annotation "Transport\CurlerRequest".
Loading history...
501
    {
502 2
        if ($this->getCountPendingQueue() > 0) {
503
            throw new QueryException('Queue must be empty, before insertBatch, need executeAsync');
504
        }
505
506 2
        if (! in_array($format, self::SUPPORTED_FORMATS, true)) {
507
            throw new QueryException('Format not support in insertBatchFiles');
508
        }
509
510 2
        if (empty($columns)) {
511
            $sql = 'INSERT INTO ' . $tableName . ' FORMAT ' . $format;
512
        } else {
513 2
            $sql = 'INSERT INTO ' . $tableName . ' ( ' . implode(',', $columns) . ' ) FORMAT ' . $format;
514
        }
515
516 2
        return $this->transport->writeStreamData($sql);
517
    }
518
519
    /**
520
     * stream Write
521
     *
522
     * @param string[] $bind
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
523
     * @return Statement
524
     * @throws Exception\TransportException
525
     */
526 1
    public function streamWrite(Stream $stream, string $sql, array $bind = [])
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::streamWrite() does not have return type hint for its return value but it should be possible to add it based on @return annotation "Statement".
Loading history...
527
    {
528 1
        if ($this->getCountPendingQueue() > 0) {
529
            throw new QueryException('Queue must be empty, before streamWrite');
530
        }
531
532 1
        return $this->transport->streamWrite($stream, $sql, $bind);
533
    }
534
535
    /**
536
     * stream Read
537
     *
538
     * @param string[] $bind
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
539
     * @return Statement
540
     */
541 1
    public function streamRead(Stream $streamRead, string $sql, array $bind = [])
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::streamRead() does not have return type hint for its return value but it should be possible to add it based on @return annotation "Statement".
Loading history...
542
    {
543 1
        if ($this->getCountPendingQueue() > 0) {
544
            throw new QueryException('Queue must be empty, before streamWrite');
545
        }
546
547 1
        return $this->transport->streamRead($streamRead, $sql, $bind);
548
    }
549
550
    /**
551
     * show databases
552
     *
553
     * @return array
0 ignored issues
show
introduced by
@return annotation of method \ClickHouseDB\Client::showDatabases() does not specify type hint for items of its traversable return value.
Loading history...
554
     */
555
    public function showDatabases()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::showDatabases() does not have return type hint for its return value but it should be possible to add it based on @return annotation "array".
Loading history...
556
    {
557
        return $this->select('show databases')->rows();
558
    }
559
560
    /**
561
     * Size of database
562
     *
563
     * @return mixed|null
564
     */
565
    public function databaseSize()
566
    {
567
        $database = $this->getSettings()->get('database');
568
569
        return $this->select(
570
            '
571
            SELECT database,formatReadableSize(sum(bytes)) as size
572
            FROM system.parts
573
            WHERE active AND database=:database
574
            GROUP BY database
575
            ',
576
            ['database' => $database]
577
        )->fetchOne();
578
    }
579
580
    /**
581
     * SHOW TABLES
582
     *
583
     * @return mixed[]
584
     */
585 1
    public function showTables()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::showTables() does not have return type hint for its return value but it should be possible to add it based on @return annotation "mixed[]".
Loading history...
586
    {
587 1
        return $this->select('SHOW TABLES')->rowsAsTree('name');
588
    }
589
590
    /**
591
     * statement = SHOW CREATE TABLE
592
     *
593
     * @return mixed
594
     */
595
    public function showCreateTable(string $table)
596
    {
597
        return $this->select('SHOW CREATE TABLE ' . $table)->fetchOne('statement');
598
    }
599
600
    /**
601
     * Size of tables
602
     *
603
     * @return mixed
604
     */
605 1
    public function tableSize(string $tableName)
606
    {
607 1
        $tables = $this->tablesSize();
608
609 1
        if (isset($tables[$tableName])) {
610 1
            return $tables[$tableName];
611
        }
612
613
        return null;
614
    }
615
616
    /**
617
     * Tables sizes
618
     *
619
     * @param bool $flatList
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
620
     * @return mixed[][]
621
     */
622 1
    public function tablesSize($flatList = false)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::tablesSize() does not have parameter type hint for its parameter $flatList but it should be possible to add it based on @param annotation "bool".
Loading history...
introduced by
Method \ClickHouseDB\Client::tablesSize() does not have return type hint for its return value but it should be possible to add it based on @return annotation "mixed[][]".
Loading history...
623
    {
624 1
        $result = $this->select('
625
        SELECT name as table,database,
626
            max(sizebytes) as sizebytes,
627
            max(size) as size,
628
            min(min_date) as min_date,
629
            max(max_date) as max_date
630
            FROM system.tables
631
            ANY LEFT JOIN 
632
            (
633
            SELECT table,database,
634
                        formatReadableSize(sum(bytes)) as size,
635
                        sum(bytes) as sizebytes,
636
                        min(min_date) as min_date,
637
                        max(max_date) as max_date
638
                        FROM system.parts 
639
                        WHERE active AND database=:database
640
                        GROUP BY table,database
641
            ) USING ( table,database )
642
            WHERE database=:database
643
            GROUP BY table,database
644
        ',
645 1
            ['database' => $this->database]);
646
647 1
        if ($flatList) {
648
            return $result->rows();
649
        }
650
651 1
        return $result->rowsAsTree('table');
652
    }
653
654
    /**
655
     * isExists
656
     *
657
     * @return array
0 ignored issues
show
introduced by
@return annotation of method \ClickHouseDB\Client::tableExists() does not specify type hint for items of its traversable return value.
Loading history...
658
     */
659
    public function tableExists(string $database, string $table)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::tableExists() does not have return type hint for its return value but it should be possible to add it based on @return annotation "array".
Loading history...
660
    {
661
        return $this->select(
662
            '
663
            SELECT *
664
            FROM system.tables 
665
            WHERE name=\'' . $table . '\' AND database=\'' . $database . '\''
666
        )->rowsAsTree('name');
667
    }
668
669
    /**
670
     * List of partitions
671
     *
672
     * @return mixed[][]
673
     */
674
    public function partitions(string $table, int $limit = null, bool $active = null)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::partitions() does not have return type hint for its return value but it should be possible to add it based on @return annotation "mixed[][]".
Loading history...
introduced by
Parameter $limit has null default value, but is not marked as nullable.
Loading history...
introduced by
Parameter $active has null default value, but is not marked as nullable.
Loading history...
675
    {
676
        $database          = $this->database;
677
        $whereActiveClause = $active === null ? '' : sprintf(' AND active = %s', (int) $active);
678
        $limitClause       = $limit !== null ? ' LIMIT ' . $limit : '';
679
680
        return $this->select(<<<CLICKHOUSE
681
SELECT *
682
FROM system.parts 
683
WHERE like(table,'%$table%') AND database='$database'$whereActiveClause
684
ORDER BY max_date $limitClause
685
CLICKHOUSE
686
        )->rowsAsTree('name');
687
    }
688
689
    /**
690
     * dropPartition
691
     * @deprecated
0 ignored issues
show
introduced by
Expected 1 lines between description and annotations, found 0.
Loading history...
introduced by
Incorrect annotations group.
Loading history...
692
     * @return Statement
693
     */
694
    public function dropPartition(string $dataBaseTableName, string $partition_id)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::dropPartition() does not have return type hint for its return value but it should be possible to add it based on @return annotation "Statement".
Loading history...
695
    {
0 ignored issues
show
Coding Style introduced by
Expected 0 blank lines after opening function brace; 1 found
Loading history...
696
697
        $partition_id = trim($partition_id, '\'');
698
        $this->getSettings()->set('replication_alter_partitions_sync', 2);
699
        $state = $this->write('ALTER TABLE {dataBaseTableName} DROP PARTITION :partion_id',
0 ignored issues
show
introduced by
Useless variable $state.
Loading history...
700
            [
701
                'dataBaseTableName' => $dataBaseTableName,
702
                'partion_id'        => $partition_id,
703
            ]);
704
705
        return $state;
706
    }
707
708
    /**
709
     * dropOldPartitions by day_ago
710
     * @deprecated
0 ignored issues
show
introduced by
Expected 1 lines between description and annotations, found 0.
Loading history...
711
     *
712
     * @return array
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
introduced by
@return annotation of method \ClickHouseDB\Client::dropOldPartitions() does not specify type hint for items of its traversable return value.
Loading history...
713
     * @throws Exception\TransportException
714
     * @throws \Exception
0 ignored issues
show
introduced by
Class \Exception should not be referenced via a fully qualified name, but via a use statement.
Loading history...
715
     */
716
    public function dropOldPartitions(string $table_name, int $days_ago, int $count_partitons_per_one = 100)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::dropOldPartitions() does not have return type hint for its return value but it should be possible to add it based on @return annotation "array".
Loading history...
717
    {
718
        $days_ago = strtotime(date('Y-m-d 00:00:00', strtotime('-' . $days_ago . ' day')));
719
720
        $drop           = [];
721
        $list_patitions = $this->partitions($table_name, $count_partitons_per_one);
722
723
        foreach ($list_patitions as $partion_id => $partition) {
724
            if (stripos($partition['engine'], 'mergetree') === false) {
725
                continue;
726
            }
727
728
            // $min_date = strtotime($partition['min_date']);
729
            $max_date = strtotime($partition['max_date']);
730
731
            if ($max_date < $days_ago) {
0 ignored issues
show
introduced by
Use early exit to reduce code nesting.
Loading history...
732
                $drop[] = $partition['partition'];
733
            }
734
        }
735
736
        $result = [];
737
        foreach ($drop as $partition_id) {
738
            $result[$partition_id] = $this->dropPartition($table_name, $partition_id);
0 ignored issues
show
Deprecated Code introduced by
The function ClickHouseDB\Client::dropPartition() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

738
            $result[$partition_id] = /** @scrutinizer ignore-deprecated */ $this->dropPartition($table_name, $partition_id);
Loading history...
739
        }
740
741
        return $result;
742
    }
743
744
    /**
745
     * Truncate ( drop all partitions )
746
     * @deprecated
0 ignored issues
show
introduced by
Expected 1 lines between description and annotations, found 0.
Loading history...
introduced by
Incorrect annotations group.
Loading history...
747
     * @return array
0 ignored issues
show
introduced by
@return annotation of method \ClickHouseDB\Client::truncateTable() does not specify type hint for items of its traversable return value.
Loading history...
748
     */
749
    public function truncateTable(string $tableName)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::truncateTable() does not have return type hint for its return value but it should be possible to add it based on @return annotation "array".
Loading history...
750
    {
751
        $partions = $this->partitions($tableName);
752
        $out      = [];
753
        foreach ($partions as $part_key => $part) {
754
            $part_id       = $part['partition'];
755
            $out[$part_id] = $this->dropPartition($tableName, $part_id);
0 ignored issues
show
Deprecated Code introduced by
The function ClickHouseDB\Client::dropPartition() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

755
            $out[$part_id] = /** @scrutinizer ignore-deprecated */ $this->dropPartition($tableName, $part_id);
Loading history...
756
        }
757
758
        return $out;
759
    }
760
761
    /**
762
     * Returns the server's uptime in seconds.
763
     *
764
     * @return int
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
765
     * @throws Exception\TransportException
766
     */
767 1
    public function getServerUptime()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::getServerUptime() does not have return type hint for its return value but it should be possible to add it based on @return annotation "int".
Loading history...
768
    {
769 1
        return $this->select('SELECT uptime() as uptime')->fetchOne('uptime');
770
    }
771
772
    /**
773
     * Returns string with the server version.
774
     */
775 1
    public function getServerVersion() : string
776
    {
777 1
        return (string) $this->select('SELECT version() as version')->fetchOne('version');
778
    }
779
780
    /**
781
     * Read system.settings table
782
     *
783
     * @return mixed[][]
784
     */
785 1
    public function getServerSystemSettings(string $like = '')
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::getServerSystemSettings() does not have return type hint for its return value but it should be possible to add it based on @return annotation "mixed[][]".
Loading history...
786
    {
787 1
        $l    = [];
788 1
        $list = $this->select('SELECT * FROM system.settings' . ($like ? ' WHERE name LIKE :like' : ''),
789 1
            ['like' => '%' . $like . '%'])->rows();
790 1
        foreach ($list as $row) {
791 1
            if (isset($row['name'])) {
0 ignored issues
show
introduced by
Use early exit to reduce code nesting.
Loading history...
792 1
                $n = $row['name'];
793 1
                unset($row['name']);
794 1
                $l[$n] = $row;
795
            }
796
        }
797
798 1
        return $l;
799
    }
800
}
801