Failed Conditions
Pull Request — master (#101)
by
unknown
02:18
created

Client::expr()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
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\Expression;
10
use ClickHouseDB\Query\Degeneration\Bindings;
0 ignored issues
show
Coding Style introduced by
Use statements should be sorted alphabetically. The first wrong one is ClickHouseDB\Query\Degeneration\Bindings.
Loading history...
11
use ClickHouseDB\Query\Degeneration\Conditions;
12
use ClickHouseDB\Query\WhereInFile;
13
use ClickHouseDB\Query\WriteToFile;
14
use ClickHouseDB\Quote\FormatLine;
15
use ClickHouseDB\Transport\Http;
16
use ClickHouseDB\Transport\Stream;
17
use function array_flip;
18
use function array_keys;
19
use function array_rand;
20
use function array_values;
21
use function count;
22
use function date;
23
use function implode;
24
use function in_array;
25
use function is_array;
26
use function is_callable;
27
use function is_file;
28
use function is_readable;
29
use function is_string;
30
use function sprintf;
31
use function stripos;
32
use function strtotime;
33
use function trim;
34
35
class Client
36
{
37
    const SUPPORTED_FORMATS = ['TabSeparated', 'TabSeparatedWithNames', 'CSV', 'CSVWithNames', 'JSONEachRow'];
0 ignored issues
show
introduced by
Constant \ClickHouseDB\Client::SUPPORTED_FORMATS visibility missing.
Loading history...
38
39
    /** @var Http */
40
    private $transport;
41
42
    /** @var string */
43
    private $connectUsername;
44
45
    /** @var string */
46
    private $connectPassword;
47
48
    /** @var string */
49
    private $connectHost;
50
51
    /** @var string */
52
    private $connectPort;
53
54
    /** @var bool */
55
    private $connectUserReadonly = false;
56
57
    /**
58
     * @param mixed[] $connectParams
59
     * @param mixed[] $settings
60
     */
61 63
    public function __construct(array $connectParams, array $settings = [])
62
    {
63 63
        if (! isset($connectParams['username'])) {
64
            throw  new \InvalidArgumentException('not set username');
0 ignored issues
show
introduced by
Class \InvalidArgumentException should not be referenced via a fully qualified name, but via a use statement.
Loading history...
65
        }
66
67 63
        if (! isset($connectParams['password'])) {
68
            throw  new \InvalidArgumentException('not set password');
0 ignored issues
show
introduced by
Class \InvalidArgumentException should not be referenced via a fully qualified name, but via a use statement.
Loading history...
69
        }
70
71 63
        if (! isset($connectParams['port'])) {
72
            throw  new \InvalidArgumentException('not set port');
0 ignored issues
show
introduced by
Class \InvalidArgumentException should not be referenced via a fully qualified name, but via a use statement.
Loading history...
73
        }
74
75 63
        if (! isset($connectParams['host'])) {
76
            throw  new \InvalidArgumentException('not set host');
0 ignored issues
show
introduced by
Class \InvalidArgumentException should not be referenced via a fully qualified name, but via a use statement.
Loading history...
77
        }
78
79 63
        $this->connectUsername = $connectParams['username'];
80 63
        $this->connectPassword = $connectParams['password'];
81 63
        $this->connectPort     = $connectParams['port'];
82 63
        $this->connectHost     = $connectParams['host'];
83
84
        // init transport class
85 63
        $this->transport = new Http(
86 63
            $this->connectHost,
87 63
            $this->connectPort,
88 63
            $this->connectUsername,
89 63
            $this->connectPassword
90
        );
91
92 63
        $this->transport->addQueryDegeneration(new Bindings());
93
94
        // apply settings to transport class
95 63
        $this->settings()->database('default');
96 63
        if (! empty($settings)) {
97 1
            $this->settings()->apply($settings);
98
        }
99
100 63
        if (isset($connectParams['readonly'])) {
101
            $this->setReadOnlyUser($connectParams['readonly']);
102
        }
103
104 63
        if (isset($connectParams['https'])) {
105
            $this->https($connectParams['https']);
106
        }
107
108 63
        $this->enableHttpCompression();
109 63
    }
110
111
    /**
112
     * if the user has only read in the config file
113
     */
114
    public function setReadOnlyUser(bool $flag)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::setReadOnlyUser() does not have void return type hint.
Loading history...
115
    {
116
        $this->connectUserReadonly = $flag;
117
        $this->settings()->setReadOnlyUser($this->connectUserReadonly);
118
    }
119
120
    /**
121
     * Clear Degeneration processing request [template ]
122
     *
123
     * @return bool
124
     */
125 1
    public function cleanQueryDegeneration()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::cleanQueryDegeneration() 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...
126
    {
127 1
        return $this->transport->cleanQueryDegeneration();
128
    }
129
130
    /**
131
     * add Degeneration processing
132
     *
133
     * @return bool
134
     */
135
    public function addQueryDegeneration(Degeneration $degeneration)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::addQueryDegeneration() 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...
136
    {
137
        return $this->transport->addQueryDegeneration($degeneration);
138
    }
139
140
    /**
141
     * add Conditions in query
142
     *
143
     * @return bool
144
     */
145 1
    public function enableQueryConditions()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::enableQueryConditions() 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...
146
    {
147 1
        return $this->transport->addQueryDegeneration(new Conditions());
148
    }
149
150
    /**
151
     * Set connection host
152
     *
153
     * @param string|string[] $host
154
     */
155
    public function setHost($host)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::setHost() does not have void return type hint.
Loading history...
156
    {
157
        if (is_array($host)) {
158
            $host = array_rand(array_flip($host));
159
        }
160
161
        $this->connectHost = $host;
162
        $this->transport()->setHost($host);
163
    }
164
165
    /**
166
     * @return Settings
167
     */
168 2
    public function setTimeout(float $timeout)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::setTimeout() does not have return type hint for its return value but it should be possible to add it based on @return annotation "Settings".
Loading history...
169
    {
170 2
        return $this->settings()->max_execution_time($timeout);
0 ignored issues
show
Bug introduced by
$timeout of type double is incompatible with the type integer expected by parameter $time of ClickHouseDB\Settings::max_execution_time(). ( Ignorable by Annotation )

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

170
        return $this->settings()->max_execution_time(/** @scrutinizer ignore-type */ $timeout);
Loading history...
171
    }
172
173
    /**
174
     * @return mixed
175
     */
176 1
    public function getTimeout()
177
    {
178 1
        return $this->settings()->getTimeOut();
179
    }
180
181
    /**
182
     * ConnectTimeOut in seconds ( support 1.5 = 1500ms )
183
     */
184 2
    public function setConnectTimeOut(float $connectTimeOut)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::setConnectTimeOut() does not have void return type hint.
Loading history...
185
    {
186 2
        $this->transport()->setConnectTimeOut($connectTimeOut);
0 ignored issues
show
Bug introduced by
$connectTimeOut of type double is incompatible with the type integer expected by parameter $connectTimeOut of ClickHouseDB\Transport\Http::setConnectTimeOut(). ( Ignorable by Annotation )

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

186
        $this->transport()->setConnectTimeOut(/** @scrutinizer ignore-type */ $connectTimeOut);
Loading history...
187 2
    }
188
189
    /**
190
     * @return int
191
     */
192 1
    public function getConnectTimeOut()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::getConnectTimeOut() 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...
193
    {
194 1
        return $this->transport()->getConnectTimeOut();
195
    }
196
197
    /**
198
     * @return Http
199
     */
200 63
    public function transport()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::transport() does not have return type hint for its return value but it should be possible to add it based on @return annotation "Http".
Loading history...
201
    {
202 63
        if (! $this->transport) {
203
            throw  new \InvalidArgumentException('Empty transport class');
0 ignored issues
show
introduced by
Class \InvalidArgumentException should not be referenced via a fully qualified name, but via a use statement.
Loading history...
204
        }
205
206 63
        return $this->transport;
207
    }
208
209
    /**
210
     * @return string
211
     */
212
    public function getConnectHost()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::getConnectHost() does not have return type hint for its return value but it should be possible to add it based on @return annotation "string".
Loading history...
213
    {
214
        return $this->connectHost;
215
    }
216
217
    /**
218
     * @return string
219
     */
220
    public function getConnectPassword()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::getConnectPassword() does not have return type hint for its return value but it should be possible to add it based on @return annotation "string".
Loading history...
221
    {
222
        return $this->connectPassword;
223
    }
224
225
    /**
226
     * @return string
227
     */
228
    public function getConnectPort()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::getConnectPort() does not have return type hint for its return value but it should be possible to add it based on @return annotation "string".
Loading history...
229
    {
230
        return $this->connectPort;
231
    }
232
233
    /**
234
     * @return string
235
     */
236
    public function getConnectUsername()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::getConnectUsername() does not have return type hint for its return value but it should be possible to add it based on @return annotation "string".
Loading history...
237
    {
238
        return $this->connectUsername;
239
    }
240
241
    /**
242
     * @return Http
243
     */
244
    public function getTransport()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::getTransport() does not have return type hint for its return value but it should be possible to add it based on @return annotation "Http".
Loading history...
245
    {
246
        return $this->transport;
247
    }
248
249
    /**
250
     * @return mixed
251
     */
252
    public function verbose()
253
    {
254
        return $this->transport()->verbose(true);
255
    }
256
257
    /**
258
     * @return Settings
259
     */
260 63
    public function settings()
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::settings() does not have return type hint for its return value but it should be possible to add it based on @return annotation "Settings".
Loading history...
261
    {
262 63
        return $this->transport()->settings();
263
    }
264
265
    /**
266
     * @return static
267
     */
268 2
    public function useSession(bool $useSessionId = false)
269
    {
270 2
        if (! $this->settings()->getSessionId()) {
271 2
            if (! $useSessionId) {
272 2
                $this->settings()->makeSessionId();
273
            } else {
274
                $this->settings()->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

274
                $this->settings()->session_id(/** @scrutinizer ignore-type */ $useSessionId);
Loading history...
275
            }
276
        }
277
278 2
        return $this;
279
    }
280
281
    /**
282
     * @return mixed
283
     */
284 2
    public function getSession()
285
    {
286 2
        return $this->settings()->getSessionId();
287
    }
288
289
    /**
290
     * Query CREATE/DROP
291
     *
292
     * @param mixed[] $bindings
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
293
     * @return Statement
294
     */
295 26
    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...
296
    {
297 26
        return $this->transport()->write($sql, $bindings, $exception);
298
    }
299
300
    /**
301
     * set db name
302
     * @return static
0 ignored issues
show
introduced by
Expected 1 lines between description and annotations, found 0.
Loading history...
303
     */
304 63
    public function database(string $db)
305
    {
306 63
        $this->settings()->database($db);
307
308 63
        return $this;
309
    }
310
311
    /**
312
     * Write to system.query_log
313
     *
314
     * @return static
315
     */
316
    public function enableLogQueries(bool $flag = true)
317
    {
318
        $this->settings()->set('log_queries', (int) $flag);
319
320
        return $this;
321
    }
322
323
    /**
324
     * Compress the result if the HTTP client said that it understands data compressed with gzip or deflate
325
     *
326
     * @return static
327
     */
328 63
    public function enableHttpCompression(bool $flag = true)
329
    {
330 63
        $this->settings()->enableHttpCompression($flag);
331
332 63
        return $this;
333
    }
334
335
    /**
336
     * Enable / Disable HTTPS
337
     *
338
     * @return static
339
     */
340 1
    public function https(bool $flag = true)
341
    {
342 1
        $this->settings()->https($flag);
343
344 1
        return $this;
345
    }
346
347
    /**
348
     * Read extremes of the result columns. They can be output in JSON-formats.
349
     *
350
     * @return static
351
     */
352 2
    public function enableExtremes(bool $flag = true)
353
    {
354 2
        $this->settings()->set('extremes', (int) $flag);
355
356 2
        return $this;
357
    }
358
359
    /**
360
     * @param mixed[] $bindings
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
361
     * @return Statement
362
     */
363 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...
364
        string $sql,
365
        array $bindings = [],
366
        WhereInFile $whereInFile = null,
0 ignored issues
show
introduced by
Parameter $whereInFile has null default value, but is not marked as nullable.
Loading history...
367
        WriteToFile $writeToFile = null
0 ignored issues
show
introduced by
Parameter $writeToFile has null default value, but is not marked as nullable.
Loading history...
368
    ) {
369 29
        return $this->transport()->select($sql, $bindings, $whereInFile, $writeToFile);
370
    }
371
372
    /**
373
     * @return bool
374
     */
375 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...
376
    {
377 10
        return $this->transport()->executeAsync();
378
    }
379
380
    /**
381
     * set progressFunction
382
     */
383 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...
384
    {
385 1
        if (! is_callable($callback)) {
386
            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...
387
        }
388
389 1
        if (! $this->settings()->is('send_progress_in_http_headers')) {
390 1
            $this->settings()->set('send_progress_in_http_headers', 1);
391
        }
392 1
        if (! $this->settings()->is('http_headers_progress_interval_ms')) {
393 1
            $this->settings()->set('http_headers_progress_interval_ms', 100);
394
        }
395
396 1
        $this->transport()->setProgressFunction($callback);
397 1
    }
398
399
    /**
400
     * prepare select
401
     *
402
     * @param mixed[] $bindings
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
403
     * @return Statement
404
     */
405 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...
406
        string $sql,
407
        array $bindings = [],
408
        WhereInFile $whereInFile = null,
0 ignored issues
show
introduced by
Parameter $whereInFile has null default value, but is not marked as nullable.
Loading history...
409
        WriteToFile $writeToFile = null
0 ignored issues
show
introduced by
Parameter $writeToFile has null default value, but is not marked as nullable.
Loading history...
410
    ) {
411 5
        return $this->transport()->selectAsync($sql, $bindings, $whereInFile, $writeToFile);
412
    }
413
414
    /**
415
     * SHOW PROCESSLIST
416
     *
417
     * @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...
418
     */
419
    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...
420
    {
421
        return $this->select('SHOW PROCESSLIST')->rows();
422
    }
423
424
    /**
425
     * show databases
426
     *
427
     * @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...
428
     */
429
    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...
430
    {
431
        return $this->select('show databases')->rows();
432
    }
433
434
    /**
435
     * statement = SHOW CREATE TABLE
436
     *
437
     * @return mixed
438
     */
439
    public function showCreateTable(string $table)
440
    {
441
        return $this->select('SHOW CREATE TABLE ' . $table)->fetchOne('statement');
442
    }
443
444
    /**
445
     * SHOW TABLES
446
     *
447
     * @return mixed[]
448
     */
449 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...
450
    {
451 1
        return $this->select('SHOW TABLES')->rowsAsTree('name');
452
    }
453
454
    /**
455
     * Get the number of simultaneous/Pending requests
456
     *
457
     * @return int
458
     */
459 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...
460
    {
461 12
        return $this->transport()->getCountPendingQueue();
462
    }
463
464
    /**
465
     * @param mixed[][] $values
466
     * @param string[]  $columns
467
     */
468 9
    public function insert(string $table, array $values, array $columns = []) : Statement
469
    {
470 9
        if (empty($values)) {
471 1
            throw QueryException::cannotInsertEmptyValues();
472
        }
473
474 8
        if (stripos($table, '`') === false && stripos($table, '.') === false) {
475 5
            $table = '`' . $table . '`'; //quote table name for dot names
476
        }
477 8
        $sql = 'INSERT INTO ' . $table;
478
479 8
        if (count($columns) !== 0) {
480 7
            $sql .= ' (`' . implode('`,`', $columns) . '`) ';
481
        }
482
483 8
        $sql .= ' VALUES ';
484
485 8
        foreach ($values as $row) {
486 8
            $sql .= ' (' . FormatLine::Insert($row) . '), ';
487
        }
488 8
        $sql = trim($sql, ', ');
489
490 8
        return $this->transport()->write($sql);
491
    }
492
493
    /**
494
     *       * Prepares the values to insert from the associative array.
495
     *       * There may be one or more lines inserted, but then the keys inside the array list must match (including in the sequence)
496
     *       *
497
     *       * @param mixed[] $values - array column_name => value (if we insert one row) or array list column_name => value if we insert many lines
498
     *       * @return mixed[][] - list of arrays - 0 => fields, 1 => list of value arrays for insertion
499
     *       */
500 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...
501
    {
502 3
        if (isset($values[0]) && is_array($values[0])) { //случай, когда много строк вставляется
503 2
            $preparedFields = array_keys($values[0]);
504 2
            $preparedValues = [];
505 2
            foreach ($values as $idx => $row) {
506 2
                $_fields = array_keys($row);
507 2
                if ($_fields !== $preparedFields) {
508 1
                    throw new QueryException(
509 1
                        sprintf(
510 1
                            'Fields not match: %s and %s on element %s',
511 1
                            implode(',', $_fields),
512 1
                            implode(',', $preparedFields),
513 1
                            $idx
514
                        )
515
                    );
516
                }
517 2
                $preparedValues[] = array_values($row);
518
            }
519
        } else {
520 1
            $preparedFields = array_keys($values);
521 1
            $preparedValues = [array_values($values)];
522
        }
523
524 2
        return [$preparedFields, $preparedValues];
525
    }
526
527
    /**
528
     * Inserts one or more rows from an associative array.
529
     * If there is a discrepancy between the keys of the value arrays (or their order) - throws an exception.
530
     *
531
     * @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...
532
     * @return Statement
533
     */
534
    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...
535
    {
536
        list($columns, $vals) = $this->prepareInsertAssocBulk($values);
0 ignored issues
show
introduced by
list(...) is forbidden, use [...] instead.
Loading history...
537
538
        return $this->insert($tableName, $vals, $columns);
539
    }
540
541
    /**
542
     * insert TabSeparated files
543
     *
544
     * @param string|string[] $fileNames
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
545
     * @param string[]        $columns
546
     * @return mixed
547
     */
548 1
    public function insertBatchTSVFiles(string $tableName, $fileNames, array $columns = [])
549
    {
550 1
        return $this->insertBatchFiles($tableName, $fileNames, $columns, 'TabSeparated');
551
    }
552
553
    /**
554
     * insert Batch Files
555
     *
556
     * @param string|string[] $fileNames
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
557
     * @param string[]        $columns
558
     * @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...
559
     * @return Statement[]
560
     * @throws Exception\TransportException
561
     */
562 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...
563
    {
564 8
        if (is_string($fileNames)) {
565
            $fileNames = [$fileNames];
566
        }
567 8
        if ($this->getCountPendingQueue() > 0) {
568
            throw new QueryException('Queue must be empty, before insertBatch, need executeAsync');
569
        }
570
571 8
        if (! in_array($format, self::SUPPORTED_FORMATS, true)) {
572
            throw new QueryException('Format not support in insertBatchFiles');
573
        }
574
575 8
        $result = [];
576
577 8
        foreach ($fileNames as $fileName) {
578 8
            if (! is_file($fileName) || ! is_readable($fileName)) {
579
                throw  new QueryException('Cant read file: ' . $fileName . ' ' . (is_file($fileName) ? '' : ' is not file'));
580
            }
581
582 8
            if (empty($columns)) {
583
                $sql = 'INSERT INTO ' . $tableName . ' FORMAT ' . $format;
584
            } else {
585 8
                $sql = 'INSERT INTO ' . $tableName . ' ( ' . implode(',', $columns) . ' ) FORMAT ' . $format;
586
            }
587 8
            $result[$fileName] = $this->transport()->writeAsyncCSV($sql, $fileName);
588
        }
589
590
        // exec
591 8
        $this->executeAsync();
592
593
        // fetch resutl
594 8
        foreach ($fileNames as $fileName) {
595 8
            if (! $result[$fileName]->isError()) {
596 6
                continue;
597
            }
598
599 2
            $result[$fileName]->error();
600
        }
601
602 6
        return $result;
603
    }
604
605
    /**
606
     * insert Batch Stream
607
     *
608
     * @param string[] $columns
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
609
     * @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...
610
     * @return Transport\CurlerRequest
611
     */
612 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...
613
    {
614 2
        if ($this->getCountPendingQueue() > 0) {
615
            throw new QueryException('Queue must be empty, before insertBatch, need executeAsync');
616
        }
617
618 2
        if (! in_array($format, self::SUPPORTED_FORMATS, true)) {
619
            throw new QueryException('Format not support in insertBatchFiles');
620
        }
621
622 2
        if (empty($columns)) {
623
            $sql = 'INSERT INTO ' . $tableName . ' FORMAT ' . $format;
624
        } else {
625 2
            $sql = 'INSERT INTO ' . $tableName . ' ( ' . implode(',', $columns) . ' ) FORMAT ' . $format;
626
        }
627
628 2
        return $this->transport()->writeStreamData($sql);
629
    }
630
631
    /**
632
     * stream Write
633
     *
634
     * @param string[] $bind
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
635
     * @return Statement
636
     * @throws Exception\TransportException
637
     */
638 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...
639
    {
640 1
        if ($this->getCountPendingQueue() > 0) {
641
            throw new QueryException('Queue must be empty, before streamWrite');
642
        }
643
644 1
        return $this->transport()->streamWrite($stream, $sql, $bind);
645
    }
646
647
    /**
648
     * stream Read
649
     *
650
     * @param string[] $bind
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
651
     * @return Statement
652
     */
653 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...
654
    {
655 1
        if ($this->getCountPendingQueue() > 0) {
656
            throw new QueryException('Queue must be empty, before streamWrite');
657
        }
658
659 1
        return $this->transport()->streamRead($streamRead, $sql, $bind);
660
    }
661
662
    /**
663
     * Size of database
664
     *
665
     * @return mixed|null
666
     */
667
    public function databaseSize()
668
    {
669
        $b = $this->settings()->getDatabase();
670
671
        return $this->select(
672
            '
673
            SELECT database,formatReadableSize(sum(bytes)) as size
674
            FROM system.parts
675
            WHERE active AND database=:database
676
            GROUP BY database
677
            ',
678
            ['database' => $b]
679
        )->fetchOne();
680
    }
681
682
    /**
683
     * Size of tables
684
     *
685
     * @return mixed
686
     */
687 1
    public function tableSize(string $tableName)
688
    {
689 1
        $tables = $this->tablesSize();
690
691 1
        if (isset($tables[$tableName])) {
692 1
            return $tables[$tableName];
693
        }
694
695
        return null;
696
    }
697
698
    /**
699
     * Ping server
700
     *
701
     * @return bool
702
     */
703 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...
704
    {
705 39
        return $this->transport()->ping();
706
    }
707
708
    /**
709
     * Tables sizes
710
     *
711
     * @param bool $flatList
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
712
     * @return mixed[][]
713
     */
714 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...
715
    {
716 1
        $result = $this->select('
717
        SELECT name as table,database,
718
            max(sizebytes) as sizebytes,
719
            max(size) as size,
720
            min(min_date) as min_date,
721
            max(max_date) as max_date
722
            FROM system.tables
723
            ANY LEFT JOIN 
724
            (
725
            SELECT table,database,
726
                        formatReadableSize(sum(bytes)) as size,
727
                        sum(bytes) as sizebytes,
728
                        min(min_date) as min_date,
729
                        max(max_date) as max_date
730
                        FROM system.parts 
731
                        WHERE active AND database=:database
732
                        GROUP BY table,database
733
            ) USING ( table,database )
734
            WHERE database=:database
735
            GROUP BY table,database
736
        ',
737 1
            ['database' => $this->settings()->getDatabase()]);
738
739 1
        if ($flatList) {
740
            return $result->rows();
741
        }
742
743 1
        return $result->rowsAsTree('table');
744
    }
745
746
    /**
747
     * isExists
748
     *
749
     * @return array
0 ignored issues
show
introduced by
@return annotation of method \ClickHouseDB\Client::isExists() does not specify type hint for items of its traversable return value.
Loading history...
750
     */
751
    public function isExists(string $database, string $table)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::isExists() 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...
752
    {
753
        return $this->select(
754
            '
755
            SELECT *
756
            FROM system.tables 
757
            WHERE name=\'' . $table . '\' AND database=\'' . $database . '\''
758
        )->rowsAsTree('name');
759
    }
760
761
    /**
762
     * List of partitions
763
     *
764
     * @return mixed[][]
765
     */
766
    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...
767
    {
768
        $database          = $this->settings()->getDatabase();
769
        $whereActiveClause = $active === null ? '' : sprintf(' AND active = %s', (int) $active);
770
        $limitClause       = $limit !== null ? ' LIMIT ' . $limit : '';
771
772
        return $this->select(<<<CLICKHOUSE
773
SELECT *
774
FROM system.parts 
775
WHERE like(table,'%$table%') AND database='$database'$whereActiveClause
776
ORDER BY max_date $limitClause
777
CLICKHOUSE
778
        )->rowsAsTree('name');
779
    }
780
781
    /**
782
     * dropPartition
783
     * @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...
784
     * @return Statement
785
     */
786
    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...
787
    {
0 ignored issues
show
Coding Style introduced by
Expected 0 blank lines after opening function brace; 1 found
Loading history...
788
789
        $partition_id = trim($partition_id, '\'');
790
        $this->settings()->set('replication_alter_partitions_sync', 2);
791
        $state = $this->write('ALTER TABLE {dataBaseTableName} DROP PARTITION :partion_id',
0 ignored issues
show
introduced by
Useless variable $state.
Loading history...
792
            [
793
                'dataBaseTableName' => $dataBaseTableName,
794
                'partion_id'        => $partition_id,
795
            ]);
796
797
        return $state;
798
    }
799
800
    /**
801
     * Truncate ( drop all partitions )
802
     * @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...
803
     * @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...
804
     */
805
    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...
806
    {
807
        $partions = $this->partitions($tableName);
808
        $out      = [];
809
        foreach ($partions as $part_key => $part) {
810
            $part_id       = $part['partition'];
811
            $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

811
            $out[$part_id] = /** @scrutinizer ignore-deprecated */ $this->dropPartition($tableName, $part_id);
Loading history...
812
        }
813
814
        return $out;
815
    }
816
817
    /**
818
     * Returns the server's uptime in seconds.
819
     *
820
     * @return int
0 ignored issues
show
introduced by
Incorrect annotations group.
Loading history...
821
     * @throws Exception\TransportException
822
     */
823 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...
824
    {
825 1
        return $this->select('SELECT uptime() as uptime')->fetchOne('uptime');
826
    }
827
828
    /**
829
     * Returns string with the server version.
830
     */
831 1
    public function getServerVersion() : string
832
    {
833 1
        return (string) $this->select('SELECT version() as version')->fetchOne('version');
834
    }
835
836
    /**
837
     * Read system.settings table
838
     *
839
     * @return mixed[][]
840
     */
841 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...
842
    {
843 1
        $l    = [];
844 1
        $list = $this->select('SELECT * FROM system.settings' . ($like ? ' WHERE name LIKE :like' : ''),
845 1
            ['like' => '%' . $like . '%'])->rows();
846 1
        foreach ($list as $row) {
847 1
            if (isset($row['name'])) {
0 ignored issues
show
introduced by
Use early exit to reduce code nesting.
Loading history...
848 1
                $n = $row['name'];
849 1
                unset($row['name']);
850 1
                $l[$n] = $row;
851
            }
852
        }
853
854 1
        return $l;
855
    }
856
857
    /**
858
     * dropOldPartitions by day_ago
859
     * @deprecated
0 ignored issues
show
introduced by
Expected 1 lines between description and annotations, found 0.
Loading history...
860
     *
861
     * @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...
862
     * @throws Exception\TransportException
863
     * @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...
864
     */
865
    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...
866
    {
867
        $days_ago = strtotime(date('Y-m-d 00:00:00', strtotime('-' . $days_ago . ' day')));
868
869
        $drop           = [];
870
        $list_patitions = $this->partitions($table_name, $count_partitons_per_one);
871
872
        foreach ($list_patitions as $partion_id => $partition) {
873
            if (stripos($partition['engine'], 'mergetree') === false) {
874
                continue;
875
            }
876
877
            // $min_date = strtotime($partition['min_date']);
878
            $max_date = strtotime($partition['max_date']);
879
880
            if ($max_date < $days_ago) {
0 ignored issues
show
introduced by
Use early exit to reduce code nesting.
Loading history...
881
                $drop[] = $partition['partition'];
882
            }
883
        }
884
885
        $result = [];
886
        foreach ($drop as $partition_id) {
887
            $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

887
            $result[$partition_id] = /** @scrutinizer ignore-deprecated */ $this->dropPartition($table_name, $partition_id);
Loading history...
888
        }
889
890
        return $result;
891
    }
892
893
    /**
894
     * Build sql expression to be used "as is" in a query
895
     *
896
     * @param string $expression
897
     *
898
     * @return \ClickHouseDB\Query\Expression
0 ignored issues
show
introduced by
Class \ClickHouseDB\Query\Expression should not be referenced via a fully qualified name, but via a use statement.
Loading history...
899
     */
900
    public function expr($expression)
0 ignored issues
show
introduced by
Method \ClickHouseDB\Client::expr() does not have parameter type hint for its parameter $expression but it should be possible to add it based on @param annotation "string".
Loading history...
introduced by
Method \ClickHouseDB\Client::expr() does not have return type hint for its return value but it should be possible to add it based on @return annotation "\ClickHouseDB\Query\Expression".
Loading history...
901
    {
902
        return new Expression($expression);
903
    }
904
}
905