Repository files navigation

Clickhouse Client

Build StatusCoverage Status

Package was written as client for Clickhouse.

Client uses Guzzle for sending Http requests to Clickhouse servers.

Requirements

php7.1

Install

Composer

composer require the-tinderbox/clickhouse-php-client

Usage

Client works with alone server and cluster. Also, client can make async select and insert (from local files) queries.

Alone server

$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass');
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server);
$client = newTinderbox\Clickhouse\Client($serverProvider);

Cluster

$testCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
'server-1' => [
'host' => '127.0.0.1',
'port' => '8123',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
'server-2' => newTinderbox\Clickhouse\Server('127.0.0.1', '8124', 'default', 'user', 'pass')
]);
$anotherCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
[
'host' => '127.0.0.1',
'port' => '8125',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
newTinderbox\Clickhouse\Server('127.0.0.1', '8126', 'default', 'user', 'pass')
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addCluster($testCluster)->addCluster($anotherCluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

Before execute any query on cluster, you should provide cluster name and client will run all queries on specified cluster.

$client->onCluster('test-cluster');

By default client will use random server in given list of servers or in specified cluster. If you want to perform request on specified server you should use using($hostname) method on client and then run query. Client will remember hostname for next queries:

$client->using('server-2')->select('select * from table');

Server tags

$firstServerOptionsWithTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('tag');
$secondServerOptionsWithAnotherTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('another-tag');
$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass', $firstServerOptionsWithTag);
$cluster = newTinderbox\Clickhouse\Cluster('cluster', [
newTinderbox\Clickhouse\Server('127.0.0.2', '8123', 'default', 'user', 'pass', $secondServerOptionsWithAnotherTag)
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server)->addCluster($cluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

To use server with tag, you should call usingServerWithTag function before execute any query.

$client->usingServerWithTag('tag');

Select queries

Any SELECT query will return instance of Result. This class implements interfaces \ArrayAccess, \Countable и \Iterator, which means that it can be used as an array.

Array with result rows can be obtained via rows property

$rows = $result->rows;
$rows = $result->getRows();

Also you can get some statistic of your query execution:

  1. Number of read rows
  2. Number of read bytes
  3. Time of query execution
  4. Rows before limit at least

Statistic can be obtained via statistic property

$statistic = $result->statistic;
$statistic = $result->getStatistic();
echo$statistic->rows;
echo$statistic->getRows();
echo$statistic->bytes;
echo$statistic->getBytes();
echo$statistic->time;
echo$statistic->getTime();
echo$statistic->rowsBeforeLimitAtLeast;
echo$statistic->getRowsBeforeLimitAtLeast();

Sync

$result = $client->readOne('select number from system.numbers limit 100');
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

Using local files

You can use local files as temporary tables in Clickhouse. You should pass as third argument array of TempTable instances. instance.

In this case will be sent one file to the server from which Clickhouse will extract data to temporary table. Structure of table will be:

  • number - UInt64

If you pass such an array as a structure:

['UInt64']

Then each column from file wil be named as _1, _2, _3.

$result = $client->readOne('select number from system.numbers where number in _numbers limit 100', newTempTable('_numbers', 'numbers.csv', [
'number' => 'UInt64'
]));
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

You can provide path to file or pass FileInterface instance as second argument.

There is some other types of file streams which could be used to send to server:

  • File - simple file stored on disk;
  • FileFromString - stream created from string. For example: new FileFromString('1'.PHP_EOL.'2'.PHP_EOL.'3'.PHP_EOL)
  • MergedFiles - stream which includes many files and merges them all in one. You should pass to constructor file path, which contains list of files which should be megred in one stream.
  • TempTable - wrapper to any of FileInterface instance and contains structure. Usefull to make inserts using with MergedFiles.

Async

Unlike the readOne method, which returns Result, the read method returns an array of Result for each executed query.

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01'"],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

In read method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Using local files

As with synchronous select request you can pass files to the server:

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01' and userId in _users", newTempTable('_users', 'users.csv', ['number' => 'UInt64'])],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

With asynchronous requests you can pass multiple files as with synchronous request.

Insert queries

Insert queries always returns true or throws exceptions in case of error.

Data can be written row by row or from local CSV or TSV files.

$client->writeOne("insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)");
$client->write([
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"]
]);
$client->writeFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.csv'),
newTinderbox\Clickhouse\Common\File('/file-2.csv')
]);
$client->insertFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.tsv'),
newTinderbox\Clickhouse\Common\File('/file-2.tsv')
], Tinderbox\Clickhouse\Common\Format::TSV);

In case of writeFiles queries executes asynchronously. If you have butch of files and you want to insert them in one insert query, you can use our ccat utility and MergedFiles instance instead of File. You should put list of files to insert into one file:

file-1.tsv
file-2.tsv

Building ccat

ccat sources placed into utils/ccat directory. Just run make && make install to build and install library into bin directory of package. There are already compiled binary of ccat in bin directory, but it may not work on some systems.

In writeFiles method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Other queries

In addition to SELECT and INSERT queries, you can execute other queries :) There is statement method for this purposes.

$client->writeOne('DROP TABLE table');

Testing

$ composer test

Roadmap

  • Add ability to save query result in local file

Contributing

Please send your own pull-requests and make suggestions on how to improve anything. We will be very grateful.

Thx!

About

Clickhouse client over HTTP

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Clickhouse Client

Build StatusCoverage Status

Package was written as client for Clickhouse.

Client uses Guzzle for sending Http requests to Clickhouse servers.

Requirements

php7.1

Install

Composer

composer require the-tinderbox/clickhouse-php-client

Usage

Client works with alone server and cluster. Also, client can make async select and insert (from local files) queries.

Alone server

$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass');
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server);
$client = newTinderbox\Clickhouse\Client($serverProvider);

Cluster

$testCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
'server-1' => [
'host' => '127.0.0.1',
'port' => '8123',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
'server-2' => newTinderbox\Clickhouse\Server('127.0.0.1', '8124', 'default', 'user', 'pass')
]);
$anotherCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
[
'host' => '127.0.0.1',
'port' => '8125',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
newTinderbox\Clickhouse\Server('127.0.0.1', '8126', 'default', 'user', 'pass')
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addCluster($testCluster)->addCluster($anotherCluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

Before execute any query on cluster, you should provide cluster name and client will run all queries on specified cluster.

$client->onCluster('test-cluster');

By default client will use random server in given list of servers or in specified cluster. If you want to perform request on specified server you should use using($hostname) method on client and then run query. Client will remember hostname for next queries:

$client->using('server-2')->select('select * from table');

Server tags

$firstServerOptionsWithTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('tag');
$secondServerOptionsWithAnotherTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('another-tag');
$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass', $firstServerOptionsWithTag);
$cluster = newTinderbox\Clickhouse\Cluster('cluster', [
newTinderbox\Clickhouse\Server('127.0.0.2', '8123', 'default', 'user', 'pass', $secondServerOptionsWithAnotherTag)
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server)->addCluster($cluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

To use server with tag, you should call usingServerWithTag function before execute any query.

$client->usingServerWithTag('tag');

Select queries

Any SELECT query will return instance of Result. This class implements interfaces \ArrayAccess, \Countable и \Iterator, which means that it can be used as an array.

Array with result rows can be obtained via rows property

$rows = $result->rows;
$rows = $result->getRows();

Also you can get some statistic of your query execution:

  1. Number of read rows
  2. Number of read bytes
  3. Time of query execution
  4. Rows before limit at least

Statistic can be obtained via statistic property

$statistic = $result->statistic;
$statistic = $result->getStatistic();
echo$statistic->rows;
echo$statistic->getRows();
echo$statistic->bytes;
echo$statistic->getBytes();
echo$statistic->time;
echo$statistic->getTime();
echo$statistic->rowsBeforeLimitAtLeast;
echo$statistic->getRowsBeforeLimitAtLeast();

Sync

$result = $client->readOne('select number from system.numbers limit 100');
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

Using local files

You can use local files as temporary tables in Clickhouse. You should pass as third argument array of TempTable instances. instance.

In this case will be sent one file to the server from which Clickhouse will extract data to temporary table. Structure of table will be:

  • number - UInt64

If you pass such an array as a structure:

['UInt64']

Then each column from file wil be named as _1, _2, _3.

$result = $client->readOne('select number from system.numbers where number in _numbers limit 100', newTempTable('_numbers', 'numbers.csv', [
'number' => 'UInt64'
]));
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

You can provide path to file or pass FileInterface instance as second argument.

There is some other types of file streams which could be used to send to server:

  • File - simple file stored on disk;
  • FileFromString - stream created from string. For example: new FileFromString('1'.PHP_EOL.'2'.PHP_EOL.'3'.PHP_EOL)
  • MergedFiles - stream which includes many files and merges them all in one. You should pass to constructor file path, which contains list of files which should be megred in one stream.
  • TempTable - wrapper to any of FileInterface instance and contains structure. Usefull to make inserts using with MergedFiles.

Async

Unlike the readOne method, which returns Result, the read method returns an array of Result for each executed query.

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01'"],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

In read method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Using local files

As with synchronous select request you can pass files to the server:

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01' and userId in _users", newTempTable('_users', 'users.csv', ['number' => 'UInt64'])],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

With asynchronous requests you can pass multiple files as with synchronous request.

Insert queries

Insert queries always returns true or throws exceptions in case of error.

Data can be written row by row or from local CSV or TSV files.

$client->writeOne("insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)");
$client->write([
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"]
]);
$client->writeFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.csv'),
newTinderbox\Clickhouse\Common\File('/file-2.csv')
]);
$client->insertFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.tsv'),
newTinderbox\Clickhouse\Common\File('/file-2.tsv')
], Tinderbox\Clickhouse\Common\Format::TSV);

In case of writeFiles queries executes asynchronously. If you have butch of files and you want to insert them in one insert query, you can use our ccat utility and MergedFiles instance instead of File. You should put list of files to insert into one file:

file-1.tsv
file-2.tsv

Building ccat

ccat sources placed into utils/ccat directory. Just run make && make install to build and install library into bin directory of package. There are already compiled binary of ccat in bin directory, but it may not work on some systems.

In writeFiles method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Other queries

In addition to SELECT and INSERT queries, you can execute other queries :) There is statement method for this purposes.

$client->writeOne('DROP TABLE table');

Testing

$ composer test

Roadmap

  • Add ability to save query result in local file

Contributing

Please send your own pull-requests and make suggestions on how to improve anything. We will be very grateful.

Thx!

About

Clickhouse client over HTTP

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Clickhouse Client

Build StatusCoverage Status

Package was written as client for Clickhouse.

Client uses Guzzle for sending Http requests to Clickhouse servers.

Requirements

php7.1

Install

Composer

composer require the-tinderbox/clickhouse-php-client

Usage

Client works with alone server and cluster. Also, client can make async select and insert (from local files) queries.

Alone server

$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass');
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server);
$client = newTinderbox\Clickhouse\Client($serverProvider);

Cluster

$testCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
'server-1' => [
'host' => '127.0.0.1',
'port' => '8123',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
'server-2' => newTinderbox\Clickhouse\Server('127.0.0.1', '8124', 'default', 'user', 'pass')
]);
$anotherCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
[
'host' => '127.0.0.1',
'port' => '8125',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
newTinderbox\Clickhouse\Server('127.0.0.1', '8126', 'default', 'user', 'pass')
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addCluster($testCluster)->addCluster($anotherCluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

Before execute any query on cluster, you should provide cluster name and client will run all queries on specified cluster.

$client->onCluster('test-cluster');

By default client will use random server in given list of servers or in specified cluster. If you want to perform request on specified server you should use using($hostname) method on client and then run query. Client will remember hostname for next queries:

$client->using('server-2')->select('select * from table');

Server tags

$firstServerOptionsWithTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('tag');
$secondServerOptionsWithAnotherTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('another-tag');
$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass', $firstServerOptionsWithTag);
$cluster = newTinderbox\Clickhouse\Cluster('cluster', [
newTinderbox\Clickhouse\Server('127.0.0.2', '8123', 'default', 'user', 'pass', $secondServerOptionsWithAnotherTag)
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server)->addCluster($cluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

To use server with tag, you should call usingServerWithTag function before execute any query.

$client->usingServerWithTag('tag');

Select queries

Any SELECT query will return instance of Result. This class implements interfaces \ArrayAccess, \Countable и \Iterator, which means that it can be used as an array.

Array with result rows can be obtained via rows property

$rows = $result->rows;
$rows = $result->getRows();

Also you can get some statistic of your query execution:

  1. Number of read rows
  2. Number of read bytes
  3. Time of query execution
  4. Rows before limit at least

Statistic can be obtained via statistic property

$statistic = $result->statistic;
$statistic = $result->getStatistic();
echo$statistic->rows;
echo$statistic->getRows();
echo$statistic->bytes;
echo$statistic->getBytes();
echo$statistic->time;
echo$statistic->getTime();
echo$statistic->rowsBeforeLimitAtLeast;
echo$statistic->getRowsBeforeLimitAtLeast();

Sync

$result = $client->readOne('select number from system.numbers limit 100');
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

Using local files

You can use local files as temporary tables in Clickhouse. You should pass as third argument array of TempTable instances. instance.

In this case will be sent one file to the server from which Clickhouse will extract data to temporary table. Structure of table will be:

  • number - UInt64

If you pass such an array as a structure:

['UInt64']

Then each column from file wil be named as _1, _2, _3.

$result = $client->readOne('select number from system.numbers where number in _numbers limit 100', newTempTable('_numbers', 'numbers.csv', [
'number' => 'UInt64'
]));
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

You can provide path to file or pass FileInterface instance as second argument.

There is some other types of file streams which could be used to send to server:

  • File - simple file stored on disk;
  • FileFromString - stream created from string. For example: new FileFromString('1'.PHP_EOL.'2'.PHP_EOL.'3'.PHP_EOL)
  • MergedFiles - stream which includes many files and merges them all in one. You should pass to constructor file path, which contains list of files which should be megred in one stream.
  • TempTable - wrapper to any of FileInterface instance and contains structure. Usefull to make inserts using with MergedFiles.

Async

Unlike the readOne method, which returns Result, the read method returns an array of Result for each executed query.

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01'"],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

In read method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Using local files

As with synchronous select request you can pass files to the server:

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01' and userId in _users", newTempTable('_users', 'users.csv', ['number' => 'UInt64'])],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

With asynchronous requests you can pass multiple files as with synchronous request.

Insert queries

Insert queries always returns true or throws exceptions in case of error.

Data can be written row by row or from local CSV or TSV files.

$client->writeOne("insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)");
$client->write([
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"]
]);
$client->writeFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.csv'),
newTinderbox\Clickhouse\Common\File('/file-2.csv')
]);
$client->insertFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.tsv'),
newTinderbox\Clickhouse\Common\File('/file-2.tsv')
], Tinderbox\Clickhouse\Common\Format::TSV);

In case of writeFiles queries executes asynchronously. If you have butch of files and you want to insert them in one insert query, you can use our ccat utility and MergedFiles instance instead of File. You should put list of files to insert into one file:

file-1.tsv
file-2.tsv

Building ccat

ccat sources placed into utils/ccat directory. Just run make && make install to build and install library into bin directory of package. There are already compiled binary of ccat in bin directory, but it may not work on some systems.

In writeFiles method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Other queries

In addition to SELECT and INSERT queries, you can execute other queries :) There is statement method for this purposes.

$client->writeOne('DROP TABLE table');

Testing

$ composer test

Roadmap

  • Add ability to save query result in local file

Contributing

Please send your own pull-requests and make suggestions on how to improve anything. We will be very grateful.

Thx!

About

Clickhouse client over HTTP

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Clickhouse Client

Build StatusCoverage Status

Package was written as client for Clickhouse.

Client uses Guzzle for sending Http requests to Clickhouse servers.

Requirements

php7.1

Install

Composer

composer require the-tinderbox/clickhouse-php-client

Usage

Client works with alone server and cluster. Also, client can make async select and insert (from local files) queries.

Alone server

$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass');
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server);
$client = newTinderbox\Clickhouse\Client($serverProvider);

Cluster

$testCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
'server-1' => [
'host' => '127.0.0.1',
'port' => '8123',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
'server-2' => newTinderbox\Clickhouse\Server('127.0.0.1', '8124', 'default', 'user', 'pass')
]);
$anotherCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
[
'host' => '127.0.0.1',
'port' => '8125',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
newTinderbox\Clickhouse\Server('127.0.0.1', '8126', 'default', 'user', 'pass')
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addCluster($testCluster)->addCluster($anotherCluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

Before execute any query on cluster, you should provide cluster name and client will run all queries on specified cluster.

$client->onCluster('test-cluster');

By default client will use random server in given list of servers or in specified cluster. If you want to perform request on specified server you should use using($hostname) method on client and then run query. Client will remember hostname for next queries:

$client->using('server-2')->select('select * from table');

Server tags

$firstServerOptionsWithTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('tag');
$secondServerOptionsWithAnotherTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('another-tag');
$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass', $firstServerOptionsWithTag);
$cluster = newTinderbox\Clickhouse\Cluster('cluster', [
newTinderbox\Clickhouse\Server('127.0.0.2', '8123', 'default', 'user', 'pass', $secondServerOptionsWithAnotherTag)
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server)->addCluster($cluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

To use server with tag, you should call usingServerWithTag function before execute any query.

$client->usingServerWithTag('tag');

Select queries

Any SELECT query will return instance of Result. This class implements interfaces \ArrayAccess, \Countable и \Iterator, which means that it can be used as an array.

Array with result rows can be obtained via rows property

$rows = $result->rows;
$rows = $result->getRows();

Also you can get some statistic of your query execution:

  1. Number of read rows
  2. Number of read bytes
  3. Time of query execution
  4. Rows before limit at least

Statistic can be obtained via statistic property

$statistic = $result->statistic;
$statistic = $result->getStatistic();
echo$statistic->rows;
echo$statistic->getRows();
echo$statistic->bytes;
echo$statistic->getBytes();
echo$statistic->time;
echo$statistic->getTime();
echo$statistic->rowsBeforeLimitAtLeast;
echo$statistic->getRowsBeforeLimitAtLeast();

Sync

$result = $client->readOne('select number from system.numbers limit 100');
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

Using local files

You can use local files as temporary tables in Clickhouse. You should pass as third argument array of TempTable instances. instance.

In this case will be sent one file to the server from which Clickhouse will extract data to temporary table. Structure of table will be:

  • number - UInt64

If you pass such an array as a structure:

['UInt64']

Then each column from file wil be named as _1, _2, _3.

$result = $client->readOne('select number from system.numbers where number in _numbers limit 100', newTempTable('_numbers', 'numbers.csv', [
'number' => 'UInt64'
]));
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

You can provide path to file or pass FileInterface instance as second argument.

There is some other types of file streams which could be used to send to server:

  • File - simple file stored on disk;
  • FileFromString - stream created from string. For example: new FileFromString('1'.PHP_EOL.'2'.PHP_EOL.'3'.PHP_EOL)
  • MergedFiles - stream which includes many files and merges them all in one. You should pass to constructor file path, which contains list of files which should be megred in one stream.
  • TempTable - wrapper to any of FileInterface instance and contains structure. Usefull to make inserts using with MergedFiles.

Async

Unlike the readOne method, which returns Result, the read method returns an array of Result for each executed query.

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01'"],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

In read method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Using local files

As with synchronous select request you can pass files to the server:

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01' and userId in _users", newTempTable('_users', 'users.csv', ['number' => 'UInt64'])],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

With asynchronous requests you can pass multiple files as with synchronous request.

Insert queries

Insert queries always returns true or throws exceptions in case of error.

Data can be written row by row or from local CSV or TSV files.

$client->writeOne("insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)");
$client->write([
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"]
]);
$client->writeFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.csv'),
newTinderbox\Clickhouse\Common\File('/file-2.csv')
]);
$client->insertFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.tsv'),
newTinderbox\Clickhouse\Common\File('/file-2.tsv')
], Tinderbox\Clickhouse\Common\Format::TSV);

In case of writeFiles queries executes asynchronously. If you have butch of files and you want to insert them in one insert query, you can use our ccat utility and MergedFiles instance instead of File. You should put list of files to insert into one file:

file-1.tsv
file-2.tsv

Building ccat

ccat sources placed into utils/ccat directory. Just run make && make install to build and install library into bin directory of package. There are already compiled binary of ccat in bin directory, but it may not work on some systems.

In writeFiles method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Other queries

In addition to SELECT and INSERT queries, you can execute other queries :) There is statement method for this purposes.

$client->writeOne('DROP TABLE table');

Testing

$ composer test

Roadmap

  • Add ability to save query result in local file

Contributing

Please send your own pull-requests and make suggestions on how to improve anything. We will be very grateful.

Thx!

About

Clickhouse client over HTTP

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Clickhouse Client

Build StatusCoverage Status

Package was written as client for Clickhouse.

Client uses Guzzle for sending Http requests to Clickhouse servers.

Requirements

php7.1

Install

Composer

composer require the-tinderbox/clickhouse-php-client

Usage

Client works with alone server and cluster. Also, client can make async select and insert (from local files) queries.

Alone server

$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass');
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server);
$client = newTinderbox\Clickhouse\Client($serverProvider);

Cluster

$testCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
'server-1' => [
'host' => '127.0.0.1',
'port' => '8123',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
'server-2' => newTinderbox\Clickhouse\Server('127.0.0.1', '8124', 'default', 'user', 'pass')
]);
$anotherCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
[
'host' => '127.0.0.1',
'port' => '8125',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
newTinderbox\Clickhouse\Server('127.0.0.1', '8126', 'default', 'user', 'pass')
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addCluster($testCluster)->addCluster($anotherCluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

Before execute any query on cluster, you should provide cluster name and client will run all queries on specified cluster.

$client->onCluster('test-cluster');

By default client will use random server in given list of servers or in specified cluster. If you want to perform request on specified server you should use using($hostname) method on client and then run query. Client will remember hostname for next queries:

$client->using('server-2')->select('select * from table');

Server tags

$firstServerOptionsWithTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('tag');
$secondServerOptionsWithAnotherTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('another-tag');
$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass', $firstServerOptionsWithTag);
$cluster = newTinderbox\Clickhouse\Cluster('cluster', [
newTinderbox\Clickhouse\Server('127.0.0.2', '8123', 'default', 'user', 'pass', $secondServerOptionsWithAnotherTag)
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server)->addCluster($cluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

To use server with tag, you should call usingServerWithTag function before execute any query.

$client->usingServerWithTag('tag');

Select queries

Any SELECT query will return instance of Result. This class implements interfaces \ArrayAccess, \Countable и \Iterator, which means that it can be used as an array.

Array with result rows can be obtained via rows property

$rows = $result->rows;
$rows = $result->getRows();

Also you can get some statistic of your query execution:

  1. Number of read rows
  2. Number of read bytes
  3. Time of query execution
  4. Rows before limit at least

Statistic can be obtained via statistic property

$statistic = $result->statistic;
$statistic = $result->getStatistic();
echo$statistic->rows;
echo$statistic->getRows();
echo$statistic->bytes;
echo$statistic->getBytes();
echo$statistic->time;
echo$statistic->getTime();
echo$statistic->rowsBeforeLimitAtLeast;
echo$statistic->getRowsBeforeLimitAtLeast();

Sync

$result = $client->readOne('select number from system.numbers limit 100');
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

Using local files

You can use local files as temporary tables in Clickhouse. You should pass as third argument array of TempTable instances. instance.

In this case will be sent one file to the server from which Clickhouse will extract data to temporary table. Structure of table will be:

  • number - UInt64

If you pass such an array as a structure:

['UInt64']

Then each column from file wil be named as _1, _2, _3.

$result = $client->readOne('select number from system.numbers where number in _numbers limit 100', newTempTable('_numbers', 'numbers.csv', [
'number' => 'UInt64'
]));
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

You can provide path to file or pass FileInterface instance as second argument.

There is some other types of file streams which could be used to send to server:

  • File - simple file stored on disk;
  • FileFromString - stream created from string. For example: new FileFromString('1'.PHP_EOL.'2'.PHP_EOL.'3'.PHP_EOL)
  • MergedFiles - stream which includes many files and merges them all in one. You should pass to constructor file path, which contains list of files which should be megred in one stream.
  • TempTable - wrapper to any of FileInterface instance and contains structure. Usefull to make inserts using with MergedFiles.

Async

Unlike the readOne method, which returns Result, the read method returns an array of Result for each executed query.

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01'"],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

In read method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Using local files

As with synchronous select request you can pass files to the server:

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01' and userId in _users", newTempTable('_users', 'users.csv', ['number' => 'UInt64'])],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

With asynchronous requests you can pass multiple files as with synchronous request.

Insert queries

Insert queries always returns true or throws exceptions in case of error.

Data can be written row by row or from local CSV or TSV files.

$client->writeOne("insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)");
$client->write([
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"]
]);
$client->writeFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.csv'),
newTinderbox\Clickhouse\Common\File('/file-2.csv')
]);
$client->insertFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.tsv'),
newTinderbox\Clickhouse\Common\File('/file-2.tsv')
], Tinderbox\Clickhouse\Common\Format::TSV);

In case of writeFiles queries executes asynchronously. If you have butch of files and you want to insert them in one insert query, you can use our ccat utility and MergedFiles instance instead of File. You should put list of files to insert into one file:

file-1.tsv
file-2.tsv

Building ccat

ccat sources placed into utils/ccat directory. Just run make && make install to build and install library into bin directory of package. There are already compiled binary of ccat in bin directory, but it may not work on some systems.

In writeFiles method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Other queries

In addition to SELECT and INSERT queries, you can execute other queries :) There is statement method for this purposes.

$client->writeOne('DROP TABLE table');

Testing

$ composer test

Roadmap

  • Add ability to save query result in local file

Contributing

Please send your own pull-requests and make suggestions on how to improve anything. We will be very grateful.

Thx!

About

Clickhouse client over HTTP

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Clickhouse Client

Build StatusCoverage Status

Package was written as client for Clickhouse.

Client uses Guzzle for sending Http requests to Clickhouse servers.

Requirements

php7.1

Install

Composer

composer require the-tinderbox/clickhouse-php-client

Usage

Client works with alone server and cluster. Also, client can make async select and insert (from local files) queries.

Alone server

$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass');
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server);
$client = newTinderbox\Clickhouse\Client($serverProvider);

Cluster

$testCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
'server-1' => [
'host' => '127.0.0.1',
'port' => '8123',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
'server-2' => newTinderbox\Clickhouse\Server('127.0.0.1', '8124', 'default', 'user', 'pass')
]);
$anotherCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
[
'host' => '127.0.0.1',
'port' => '8125',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
newTinderbox\Clickhouse\Server('127.0.0.1', '8126', 'default', 'user', 'pass')
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addCluster($testCluster)->addCluster($anotherCluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

Before execute any query on cluster, you should provide cluster name and client will run all queries on specified cluster.

$client->onCluster('test-cluster');

By default client will use random server in given list of servers or in specified cluster. If you want to perform request on specified server you should use using($hostname) method on client and then run query. Client will remember hostname for next queries:

$client->using('server-2')->select('select * from table');

Server tags

$firstServerOptionsWithTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('tag');
$secondServerOptionsWithAnotherTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('another-tag');
$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass', $firstServerOptionsWithTag);
$cluster = newTinderbox\Clickhouse\Cluster('cluster', [
newTinderbox\Clickhouse\Server('127.0.0.2', '8123', 'default', 'user', 'pass', $secondServerOptionsWithAnotherTag)
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server)->addCluster($cluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

To use server with tag, you should call usingServerWithTag function before execute any query.

$client->usingServerWithTag('tag');

Select queries

Any SELECT query will return instance of Result. This class implements interfaces \ArrayAccess, \Countable и \Iterator, which means that it can be used as an array.

Array with result rows can be obtained via rows property

$rows = $result->rows;
$rows = $result->getRows();

Also you can get some statistic of your query execution:

  1. Number of read rows
  2. Number of read bytes
  3. Time of query execution
  4. Rows before limit at least

Statistic can be obtained via statistic property

$statistic = $result->statistic;
$statistic = $result->getStatistic();
echo$statistic->rows;
echo$statistic->getRows();
echo$statistic->bytes;
echo$statistic->getBytes();
echo$statistic->time;
echo$statistic->getTime();
echo$statistic->rowsBeforeLimitAtLeast;
echo$statistic->getRowsBeforeLimitAtLeast();

Sync

$result = $client->readOne('select number from system.numbers limit 100');
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

Using local files

You can use local files as temporary tables in Clickhouse. You should pass as third argument array of TempTable instances. instance.

In this case will be sent one file to the server from which Clickhouse will extract data to temporary table. Structure of table will be:

  • number - UInt64

If you pass such an array as a structure:

['UInt64']

Then each column from file wil be named as _1, _2, _3.

$result = $client->readOne('select number from system.numbers where number in _numbers limit 100', newTempTable('_numbers', 'numbers.csv', [
'number' => 'UInt64'
]));
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

You can provide path to file or pass FileInterface instance as second argument.

There is some other types of file streams which could be used to send to server:

  • File - simple file stored on disk;
  • FileFromString - stream created from string. For example: new FileFromString('1'.PHP_EOL.'2'.PHP_EOL.'3'.PHP_EOL)
  • MergedFiles - stream which includes many files and merges them all in one. You should pass to constructor file path, which contains list of files which should be megred in one stream.
  • TempTable - wrapper to any of FileInterface instance and contains structure. Usefull to make inserts using with MergedFiles.

Async

Unlike the readOne method, which returns Result, the read method returns an array of Result for each executed query.

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01'"],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

In read method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Using local files

As with synchronous select request you can pass files to the server:

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01' and userId in _users", newTempTable('_users', 'users.csv', ['number' => 'UInt64'])],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

With asynchronous requests you can pass multiple files as with synchronous request.

Insert queries

Insert queries always returns true or throws exceptions in case of error.

Data can be written row by row or from local CSV or TSV files.

$client->writeOne("insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)");
$client->write([
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"]
]);
$client->writeFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.csv'),
newTinderbox\Clickhouse\Common\File('/file-2.csv')
]);
$client->insertFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.tsv'),
newTinderbox\Clickhouse\Common\File('/file-2.tsv')
], Tinderbox\Clickhouse\Common\Format::TSV);

In case of writeFiles queries executes asynchronously. If you have butch of files and you want to insert them in one insert query, you can use our ccat utility and MergedFiles instance instead of File. You should put list of files to insert into one file:

file-1.tsv
file-2.tsv

Building ccat

ccat sources placed into utils/ccat directory. Just run make && make install to build and install library into bin directory of package. There are already compiled binary of ccat in bin directory, but it may not work on some systems.

In writeFiles method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Other queries

In addition to SELECT and INSERT queries, you can execute other queries :) There is statement method for this purposes.

$client->writeOne('DROP TABLE table');

Testing

$ composer test

Roadmap

  • Add ability to save query result in local file

Contributing

Please send your own pull-requests and make suggestions on how to improve anything. We will be very grateful.

Thx!

About

Clickhouse client over HTTP

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Clickhouse Client

Build StatusCoverage Status

Package was written as client for Clickhouse.

Client uses Guzzle for sending Http requests to Clickhouse servers.

Requirements

php7.1

Install

Composer

composer require the-tinderbox/clickhouse-php-client

Usage

Client works with alone server and cluster. Also, client can make async select and insert (from local files) queries.

Alone server

$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass');
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server);
$client = newTinderbox\Clickhouse\Client($serverProvider);

Cluster

$testCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
'server-1' => [
'host' => '127.0.0.1',
'port' => '8123',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
'server-2' => newTinderbox\Clickhouse\Server('127.0.0.1', '8124', 'default', 'user', 'pass')
]);
$anotherCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
[
'host' => '127.0.0.1',
'port' => '8125',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
newTinderbox\Clickhouse\Server('127.0.0.1', '8126', 'default', 'user', 'pass')
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addCluster($testCluster)->addCluster($anotherCluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

Before execute any query on cluster, you should provide cluster name and client will run all queries on specified cluster.

$client->onCluster('test-cluster');

By default client will use random server in given list of servers or in specified cluster. If you want to perform request on specified server you should use using($hostname) method on client and then run query. Client will remember hostname for next queries:

$client->using('server-2')->select('select * from table');

Server tags

$firstServerOptionsWithTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('tag');
$secondServerOptionsWithAnotherTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('another-tag');
$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass', $firstServerOptionsWithTag);
$cluster = newTinderbox\Clickhouse\Cluster('cluster', [
newTinderbox\Clickhouse\Server('127.0.0.2', '8123', 'default', 'user', 'pass', $secondServerOptionsWithAnotherTag)
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server)->addCluster($cluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

To use server with tag, you should call usingServerWithTag function before execute any query.

$client->usingServerWithTag('tag');

Select queries

Any SELECT query will return instance of Result. This class implements interfaces \ArrayAccess, \Countable и \Iterator, which means that it can be used as an array.

Array with result rows can be obtained via rows property

$rows = $result->rows;
$rows = $result->getRows();

Also you can get some statistic of your query execution:

  1. Number of read rows
  2. Number of read bytes
  3. Time of query execution
  4. Rows before limit at least

Statistic can be obtained via statistic property

$statistic = $result->statistic;
$statistic = $result->getStatistic();
echo$statistic->rows;
echo$statistic->getRows();
echo$statistic->bytes;
echo$statistic->getBytes();
echo$statistic->time;
echo$statistic->getTime();
echo$statistic->rowsBeforeLimitAtLeast;
echo$statistic->getRowsBeforeLimitAtLeast();

Sync

$result = $client->readOne('select number from system.numbers limit 100');
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

Using local files

You can use local files as temporary tables in Clickhouse. You should pass as third argument array of TempTable instances. instance.

In this case will be sent one file to the server from which Clickhouse will extract data to temporary table. Structure of table will be:

  • number - UInt64

If you pass such an array as a structure:

['UInt64']

Then each column from file wil be named as _1, _2, _3.

$result = $client->readOne('select number from system.numbers where number in _numbers limit 100', newTempTable('_numbers', 'numbers.csv', [
'number' => 'UInt64'
]));
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

You can provide path to file or pass FileInterface instance as second argument.

There is some other types of file streams which could be used to send to server:

  • File - simple file stored on disk;
  • FileFromString - stream created from string. For example: new FileFromString('1'.PHP_EOL.'2'.PHP_EOL.'3'.PHP_EOL)
  • MergedFiles - stream which includes many files and merges them all in one. You should pass to constructor file path, which contains list of files which should be megred in one stream.
  • TempTable - wrapper to any of FileInterface instance and contains structure. Usefull to make inserts using with MergedFiles.

Async

Unlike the readOne method, which returns Result, the read method returns an array of Result for each executed query.

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01'"],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

In read method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Using local files

As with synchronous select request you can pass files to the server:

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01' and userId in _users", newTempTable('_users', 'users.csv', ['number' => 'UInt64'])],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

With asynchronous requests you can pass multiple files as with synchronous request.

Insert queries

Insert queries always returns true or throws exceptions in case of error.

Data can be written row by row or from local CSV or TSV files.

$client->writeOne("insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)");
$client->write([
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"]
]);
$client->writeFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.csv'),
newTinderbox\Clickhouse\Common\File('/file-2.csv')
]);
$client->insertFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.tsv'),
newTinderbox\Clickhouse\Common\File('/file-2.tsv')
], Tinderbox\Clickhouse\Common\Format::TSV);

In case of writeFiles queries executes asynchronously. If you have butch of files and you want to insert them in one insert query, you can use our ccat utility and MergedFiles instance instead of File. You should put list of files to insert into one file:

file-1.tsv
file-2.tsv

Building ccat

ccat sources placed into utils/ccat directory. Just run make && make install to build and install library into bin directory of package. There are already compiled binary of ccat in bin directory, but it may not work on some systems.

In writeFiles method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Other queries

In addition to SELECT and INSERT queries, you can execute other queries :) There is statement method for this purposes.

$client->writeOne('DROP TABLE table');

Testing

$ composer test

Roadmap

  • Add ability to save query result in local file

Contributing

Please send your own pull-requests and make suggestions on how to improve anything. We will be very grateful.

Thx!

About

Clickhouse client over HTTP

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Clickhouse Client

Build StatusCoverage Status

Package was written as client for Clickhouse.

Client uses Guzzle for sending Http requests to Clickhouse servers.

Requirements

php7.1

Install

Composer

composer require the-tinderbox/clickhouse-php-client

Usage

Client works with alone server and cluster. Also, client can make async select and insert (from local files) queries.

Alone server

$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass');
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server);
$client = newTinderbox\Clickhouse\Client($serverProvider);

Cluster

$testCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
'server-1' => [
'host' => '127.0.0.1',
'port' => '8123',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
'server-2' => newTinderbox\Clickhouse\Server('127.0.0.1', '8124', 'default', 'user', 'pass')
]);
$anotherCluster = newTinderbox\Clickhouse\Cluster('cluster-name', [
[
'host' => '127.0.0.1',
'port' => '8125',
'database' => 'default',
'user' => 'user',
'password' => 'pass'
],
newTinderbox\Clickhouse\Server('127.0.0.1', '8126', 'default', 'user', 'pass')
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addCluster($testCluster)->addCluster($anotherCluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

Before execute any query on cluster, you should provide cluster name and client will run all queries on specified cluster.

$client->onCluster('test-cluster');

By default client will use random server in given list of servers or in specified cluster. If you want to perform request on specified server you should use using($hostname) method on client and then run query. Client will remember hostname for next queries:

$client->using('server-2')->select('select * from table');

Server tags

$firstServerOptionsWithTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('tag');
$secondServerOptionsWithAnotherTag = (new \Tinderbox\Clickhouse\Common\ServerOptions())->setTag('another-tag');
$server = newTinderbox\Clickhouse\Server('127.0.0.1', '8123', 'default', 'user', 'pass', $firstServerOptionsWithTag);
$cluster = newTinderbox\Clickhouse\Cluster('cluster', [
newTinderbox\Clickhouse\Server('127.0.0.2', '8123', 'default', 'user', 'pass', $secondServerOptionsWithAnotherTag)
]);
$serverProvider = (newTinderbox\Clickhouse\ServerProvider())->addServer($server)->addCluster($cluster);
$client = (newTinderbox\Clickhouse\Client($serverProvider));

To use server with tag, you should call usingServerWithTag function before execute any query.

$client->usingServerWithTag('tag');

Select queries

Any SELECT query will return instance of Result. This class implements interfaces \ArrayAccess, \Countable и \Iterator, which means that it can be used as an array.

Array with result rows can be obtained via rows property

$rows = $result->rows;
$rows = $result->getRows();

Also you can get some statistic of your query execution:

  1. Number of read rows
  2. Number of read bytes
  3. Time of query execution
  4. Rows before limit at least

Statistic can be obtained via statistic property

$statistic = $result->statistic;
$statistic = $result->getStatistic();
echo$statistic->rows;
echo$statistic->getRows();
echo$statistic->bytes;
echo$statistic->getBytes();
echo$statistic->time;
echo$statistic->getTime();
echo$statistic->rowsBeforeLimitAtLeast;
echo$statistic->getRowsBeforeLimitAtLeast();

Sync

$result = $client->readOne('select number from system.numbers limit 100');
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

Using local files

You can use local files as temporary tables in Clickhouse. You should pass as third argument array of TempTable instances. instance.

In this case will be sent one file to the server from which Clickhouse will extract data to temporary table. Structure of table will be:

  • number - UInt64

If you pass such an array as a structure:

['UInt64']

Then each column from file wil be named as _1, _2, _3.

$result = $client->readOne('select number from system.numbers where number in _numbers limit 100', newTempTable('_numbers', 'numbers.csv', [
'number' => 'UInt64'
]));
foreach ($resultas$number) {
echo$number['number'].PHP_EOL;
}

You can provide path to file or pass FileInterface instance as second argument.

There is some other types of file streams which could be used to send to server:

  • File - simple file stored on disk;
  • FileFromString - stream created from string. For example: new FileFromString('1'.PHP_EOL.'2'.PHP_EOL.'3'.PHP_EOL)
  • MergedFiles - stream which includes many files and merges them all in one. You should pass to constructor file path, which contains list of files which should be megred in one stream.
  • TempTable - wrapper to any of FileInterface instance and contains structure. Usefull to make inserts using with MergedFiles.

Async

Unlike the readOne method, which returns Result, the read method returns an array of Result for each executed query.

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01'"],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

In read method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Using local files

As with synchronous select request you can pass files to the server:

list($clicks, $visits, $views) = $client->read([
['query' => "select * from clicks where date = '2017-01-01' and userId in _users", newTempTable('_users', 'users.csv', ['number' => 'UInt64'])],
['query' => "select * from visits where date = '2017-01-01'"],
['query' => "select * from views where date = '2017-01-01'"],
]);
foreach ($clicksas$click) {
echo$click['date'].PHP_EOL;
}

With asynchronous requests you can pass multiple files as with synchronous request.

Insert queries

Insert queries always returns true or throws exceptions in case of error.

Data can be written row by row or from local CSV or TSV files.

$client->writeOne("insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)");
$client->write([
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"],
['query' => "insert into table (date, column) values ('2017-01-01',1), ('2017-01-02',2)"]
]);
$client->writeFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.csv'),
newTinderbox\Clickhouse\Common\File('/file-2.csv')
]);
$client->insertFiles('table', ['date', 'column'], [
newTinderbox\Clickhouse\Common\File('/file-1.tsv'),
newTinderbox\Clickhouse\Common\File('/file-2.tsv')
], Tinderbox\Clickhouse\Common\Format::TSV);

In case of writeFiles queries executes asynchronously. If you have butch of files and you want to insert them in one insert query, you can use our ccat utility and MergedFiles instance instead of File. You should put list of files to insert into one file:

file-1.tsv
file-2.tsv

Building ccat

ccat sources placed into utils/ccat directory. Just run make && make install to build and install library into bin directory of package. There are already compiled binary of ccat in bin directory, but it may not work on some systems.

In writeFiles method, you can pass the parameter $concurrency which is responsible for the maximum simultaneous number of requests.

Other queries

In addition to SELECT and INSERT queries, you can execute other queries :) There is statement method for this purposes.

$client->writeOne('DROP TABLE table');

Testing

$ composer test

Roadmap

  • Add ability to save query result in local file

Contributing

Please send your own pull-requests and make suggestions on how to improve anything. We will be very grateful.

Thx!

About

Clickhouse client over HTTP

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages