├── .coveralls.yml
├── .gitignore
├── .hhconfig
├── .scrutinizer.yml
├── .sensiolabs.yml
├── .styleci.yml
├── .travis.yml
├── LICENSE
├── README.md
├── composer.json
├── example
└── client.php
├── nitpick.json
├── phpcs.xml
├── phpmd.xml
├── phpunit.xml
├── src
├── ClientSession.php
├── Column.php
├── Exception
│ ├── QueryErrorException.php
│ └── RequestFailedException.php
├── FixData.php
├── LoggerClient.php
├── PrestoHeaders.php
├── QueryError.php
├── QueryResult.php
├── ResultsSession.php
├── Session
│ ├── AbstractKeyValueStorage.php
│ ├── PreparedStatement.php
│ └── Property.php
├── StatementClient.php
└── StatementStats.php
└── tests
├── ClientSessionTest.php
├── LoggerClientTest.php
├── MockClientTrait.php
├── ResultsSessionTest.php
├── StatementClientTest.php
├── TestReflectionTrait.php
├── build
└── .gitignore
└── data
├── error.json
├── fourth_response.json
├── next_response.json
├── success.json
└── third_response.json
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | service_name: travis-ci
2 | coverage_clover: tests/build/clover.xml
3 | json_path: tests/build/coveralls-upload.json
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | composer.lock
2 | composer.phar
3 | vendor
4 |
--------------------------------------------------------------------------------
/.hhconfig:
--------------------------------------------------------------------------------
1 | assume_php=false
2 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | tools:
2 | php_code_sniffer: true
3 | php_cpd: true
4 | php_loc: true
5 | php_mess_detector: true
6 | php_pdepend: true
7 | php_analyzer: true
8 | sensiolabs_security_checker: true
9 | filter:
10 | paths: [src/*]
11 | checks:
12 | php:
13 | code_rating: true
14 | duplication: true
15 |
--------------------------------------------------------------------------------
/.sensiolabs.yml:
--------------------------------------------------------------------------------
1 | global_exclude_dirs:
2 | - vendor
3 | - tests
4 |
--------------------------------------------------------------------------------
/.styleci.yml:
--------------------------------------------------------------------------------
1 | preset: psr2
2 | finder:
3 | exclude:
4 | - example
5 | - tests
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 | sudo: false
3 | php:
4 | - 7.0
5 | - 7.1
6 | - 7.2
7 | - 7.3
8 | - nightly
9 | before_script:
10 | - composer self-update
11 | - composer install --prefer-dist --no-interaction
12 | script:
13 | - chmod -R 777 tests/build
14 | - ./vendor/bin/phpunit --coverage-clover tests/build/clover.xml
15 | after_script:
16 | - if [[ ${TRAVIS_PHP_VERSION:0:3} == "7.1" ]]; then php vendor/bin/coveralls -v; fi
17 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2017 Yuuki Takezawa
2 |
3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4 |
5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6 |
7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8 |
9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10 |
11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
12 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
13 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
14 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
15 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
16 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ytake\PrestoClient
2 |
3 | [](https://travis-ci.org/ytake/php-presto-client)
4 | [](https://coveralls.io/r/ytake/php-presto-client?branch=master)
5 | [](https://scrutinizer-ci.com/g/ytake/php-presto-client/?branch=master)
6 |
7 | [](https://packagist.org/packages/ytake/php-presto-client)
8 | [](https://packagist.org/packages/ytake/php-presto-client)
9 | [](https://packagist.org/packages/ytake/php-presto-client)
10 | [](https://styleci.io/repos/94699825)
11 |
12 | [](https://insight.sensiolabs.com/projects/9a13a5c0-7588-459f-835e-d73dabd22843)
13 |
14 | prestodb http protocol client for php
15 |
16 | [prestodb](https://prestodb.io/)
17 |
18 | ## What is Presto
19 |
20 | Presto is an open source distributed SQL query engine for running interactive analytic queries against data sources of all sizes ranging from gigabytes to petabytes.
21 |
22 | ## Install
23 |
24 | *required >= PHP 7.0*
25 |
26 | ```bash
27 | $ composer require ytake/php-presto-client
28 | ```
29 |
30 | ## Usage
31 |
32 | ### Standard
33 |
34 | ```php
35 | execute();
43 | // next call uri
44 | $client->advance();
45 |
46 | /** @var \Ytake\PrestoClient\QueryResult $result */
47 | // current result
48 | $result = $client->current();
49 |
50 | // request cancel
51 | $client->cancelLeafStage();
52 | ```
53 |
54 | ### bulk operations
55 |
56 | ```php
57 | execute()->yieldResults();
66 |
67 | // array
68 | $result = $resultSession->execute()->getResults();
69 | ```
70 |
71 | ## Fetch Styles
72 |
73 | ### FixData Object
74 |
75 | ```php
76 | execute()->yieldResults();
84 | /** @var \Ytake\PrestoClient\QueryResult $row */
85 | foreach ($result as $row) {
86 | foreach ($row->yieldData() as $yieldRow) {
87 | if ($yieldRow instanceof \Ytake\PrestoClient\FixData) {
88 | var_dump($yieldRow->offsetGet('column_name'), $yieldRow['column_name']);
89 | }
90 | }
91 | }
92 | ```
93 |
94 | ### Array Keys
95 |
96 | ```php
97 | execute()->yieldResults();
105 | /** @var \Ytake\PrestoClient\QueryResult $row */
106 | foreach ($result as $row) {
107 | /** @var array $item */
108 | foreach ($row->yieldDataArray() as $item) {
109 | if (!is_null($item)) {
110 | var_dump($item);
111 | }
112 | }
113 | }
114 | ```
115 |
116 | ### Mapping Class
117 |
118 | ```php
119 | execute()->yieldResults();
134 | /** @var \Ytake\PrestoClient\QueryResult $row */
135 | foreach ($result as $row) {
136 | foreach($row->yieldObject(Testing::class) as $object) {
137 | if ($object instanceof Testing) {
138 | var_dump($object);
139 | }
140 | }
141 | }
142 | ```
143 |
144 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ytake/php-presto-client",
3 | "description": "php prestodb client",
4 | "minimum-stability": "stable",
5 | "keywords": ["prestodb"],
6 | "license": "BSD-3-Clause",
7 | "authors": [
8 | {
9 | "name": "yuuki takezawa",
10 | "email": "yuuki.takezawa@comnect.jp.net"
11 | }
12 | ],
13 | "require": {
14 | "php": ">=7.0.0",
15 | "ext-curl": "*",
16 | "psr/log": "~1.0",
17 | "ramsey/uuid": "^3.0",
18 | "guzzlehttp/guzzle": "^6.2",
19 | "fig/http-message-util": "^1.1"
20 | },
21 | "require-dev": {
22 | "phpunit/phpunit": "~6.0",
23 | "satooshi/php-coveralls": "*",
24 | "phpmd/phpmd": "@stable",
25 | "squizlabs/php_codesniffer": "~2.7",
26 | "sebastian/phpcpd": "*",
27 | "phploc/phploc": "*",
28 | "pdepend/pdepend" : "^2.2.4",
29 | "sensiolabs/security-checker": "^4.0.0",
30 | "monolog/monolog": "^1.22"
31 | },
32 | "autoload": {
33 | "psr-4": {
34 | "Ytake\\PrestoClient\\": "src/"
35 | }
36 | },
37 | "autoload-dev": {
38 | "files": [
39 | "tests/MockClientTrait.php",
40 | "tests/TestReflectionTrait.php"
41 | ]
42 | },
43 | "scripts": {
44 | "ci": [
45 | "./vendor/bin/phpunit",
46 | "./vendor/bin/phpcpd src/",
47 | "./vendor/bin/phploc src/ --log-xml=tests/build/phploc.xml"
48 | ],
49 | "phpcs": "./vendor/bin/phpcs src/ --report-full --report-source --standard=PSR2 --colors",
50 | "security-checker": "./vendor/bin/security-checker security:check composer.lock"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/example/client.php:
--------------------------------------------------------------------------------
1 | execute();
9 | // next call uri
10 | $client->advance();
11 | // request cancel
12 | $client->cancelLeafStage();
13 | $client->advance();
14 | $client->close();
15 |
--------------------------------------------------------------------------------
/nitpick.json:
--------------------------------------------------------------------------------
1 | {
2 | "ignore": [
3 | "tests/*",
4 | "example/*"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/phpmd.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | ./tests/
16 |
17 |
18 |
19 |
20 | ./src/
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/ClientSession.php:
--------------------------------------------------------------------------------
1 |
28 | */
29 | class ClientSession
30 | {
31 | /** @var string */
32 | protected $host;
33 |
34 | /** @var string */
35 | protected $catalog;
36 |
37 | /** @var UuidInterface */
38 | protected $transactionId;
39 |
40 | /** @var string */
41 | protected $schema = 'default';
42 |
43 | /** @var string */
44 | protected $header = [];
45 |
46 | /** @var string */
47 | protected $user = 'presto';
48 |
49 | /** @var string */
50 | protected $source = PrestoHeaders::PRESTO_SOURCE_VALUE;
51 |
52 | /** @var Property[] */
53 | protected $property = [];
54 |
55 | /** @var PreparedStatement[] */
56 | protected $preparedStatement = [];
57 |
58 | /**
59 | * PrestoSession constructor.
60 | *
61 | * @param string $host
62 | * @param string $catalog
63 | */
64 | public function __construct(string $host, string $catalog)
65 | {
66 | $this->host = $host;
67 | $this->catalog = $catalog;
68 | }
69 |
70 | /**
71 | * @param string $schema
72 | */
73 | public function setSchema(string $schema)
74 | {
75 | $this->schema = $schema;
76 | }
77 |
78 | /**
79 | * @param array $header
80 | */
81 | public function setHeader(array $header)
82 | {
83 | $this->header = $header;
84 | }
85 |
86 | /**
87 | * @param string $user
88 | */
89 | public function setUser(string $user)
90 | {
91 | $this->user = $user;
92 | }
93 |
94 | /**
95 | * @param string $source
96 | */
97 | public function setSource(string $source)
98 | {
99 | $this->source = $source;
100 | }
101 |
102 | /**
103 | * @param UuidInterface $transactionId
104 | */
105 | public function setTransactionId(UuidInterface $transactionId)
106 | {
107 | $this->transactionId = $transactionId;
108 | }
109 |
110 | /**
111 | * @param Property $property
112 | */
113 | public function setProperty(Property $property)
114 | {
115 | $this->property[] = $property;
116 | }
117 |
118 | /**
119 | * @param PreparedStatement $preparedStatement
120 | */
121 | public function setPreparedStatement(PreparedStatement $preparedStatement)
122 | {
123 | $this->preparedStatement[] = $preparedStatement;
124 | }
125 |
126 | /**
127 | * @return Property[]
128 | */
129 | public function getProperty(): array
130 | {
131 | return $this->property;
132 | }
133 |
134 | /**
135 | * @return PreparedStatement[]
136 | */
137 | public function getPreparedStatement(): array
138 | {
139 | return $this->preparedStatement;
140 | }
141 |
142 | /**
143 | * @return string
144 | */
145 | public function getHost(): string
146 | {
147 | return $this->host;
148 | }
149 |
150 | /**
151 | * @return string
152 | */
153 | public function getCatalog(): string
154 | {
155 | return $this->catalog;
156 | }
157 |
158 | /**
159 | * @return array
160 | */
161 | public function getHeader(): array
162 | {
163 | return $this->header;
164 | }
165 |
166 | /**
167 | * @return string
168 | */
169 | public function getSchema(): string
170 | {
171 | return $this->schema;
172 | }
173 |
174 | /**
175 | * @return string
176 | */
177 | public function getUser(): string
178 | {
179 | return $this->user;
180 | }
181 |
182 | /**
183 | * @return string
184 | */
185 | public function getSource(): string
186 | {
187 | return $this->source;
188 | }
189 |
190 | /**
191 | * @return UuidInterface|null
192 | */
193 | public function getTransactionId()
194 | {
195 | return $this->transactionId;
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/src/Column.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | final class Column
26 | {
27 | /** @var string */
28 | private $name = '';
29 |
30 | /** @var string */
31 | private $type = '';
32 |
33 | /** @var \stdClass */
34 | private $typeSignature;
35 |
36 | /**
37 | * Column constructor.
38 | *
39 | * @param \stdClass $jsonContent
40 | */
41 | public function __construct(\stdClass $jsonContent)
42 | {
43 | $this->name = $jsonContent->name;
44 | $this->type = $jsonContent->type;
45 | $this->typeSignature = $jsonContent->typeSignature;
46 | }
47 |
48 | /**
49 | * @return string
50 | */
51 | public function getName(): string
52 | {
53 | return $this->name;
54 | }
55 |
56 | /**
57 | * @return string
58 | */
59 | public function getType(): string
60 | {
61 | return $this->type;
62 | }
63 |
64 | /**
65 | * @return mixed
66 | */
67 | public function getTypeSignature()
68 | {
69 | return $this->typeSignature;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Exception/QueryErrorException.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | final class QueryErrorException extends \Exception
26 | {
27 | }
28 |
--------------------------------------------------------------------------------
/src/Exception/RequestFailedException.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | final class RequestFailedException extends \RuntimeException
26 | {
27 | }
28 |
--------------------------------------------------------------------------------
/src/FixData.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | final class FixData implements \ArrayAccess
26 | {
27 | /**
28 | * @param string $column
29 | * @param $value
30 | */
31 | public function add(string $column, $value)
32 | {
33 | $this->$column = $value;
34 | }
35 |
36 | /**
37 | * @param mixed $offset
38 | *
39 | * @return bool
40 | */
41 | public function offsetExists($offset)
42 | {
43 | return isset($this->$offset);
44 | }
45 |
46 | /**
47 | * @param string $offset
48 | *
49 | * @return mixed|null
50 | */
51 | public function offsetGet($offset)
52 | {
53 | return $this->$offset ?? null;
54 | }
55 |
56 | /**
57 | * @param mixed $offset
58 | * @param mixed $value
59 | */
60 | public function offsetSet($offset, $value)
61 | {
62 | $this->$offset = $value;
63 | }
64 |
65 | /**
66 | * @param string $offset
67 | */
68 | public function offsetUnset($offset)
69 | {
70 | unset($this->$offset);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/LoggerClient.php:
--------------------------------------------------------------------------------
1 |
31 | */
32 | class LoggerClient
33 | {
34 | /** @var LoggerInterface */
35 | protected $logger;
36 |
37 | /** @var string */
38 | protected $template = '{date_common_log} {uri} {req_headers} {req_body} {res_headers}';
39 |
40 | /**
41 | * LoggerClient constructor.
42 | *
43 | * @param LoggerInterface $logger
44 | */
45 | public function __construct(LoggerInterface $logger)
46 | {
47 | $this->logger = $logger;
48 | }
49 |
50 | /**
51 | * @param callable|null $handler
52 | *
53 | * @return ClientInterface
54 | */
55 | public function client(callable $handler = null): ClientInterface
56 | {
57 | $handlerStack = HandlerStack::create($handler);
58 | $handlerStack->push(
59 | Middleware::log($this->logger, new MessageFormatter($this->template))
60 | );
61 | return new Client([
62 | 'handler' => $handlerStack,
63 | ]);
64 | }
65 |
66 | /**
67 | * @codeCoverageIgnore
68 | * @param string $template
69 | */
70 | public function setTemplate(string $template)
71 | {
72 | $this->template = $template;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/PrestoHeaders.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | final class PrestoHeaders
26 | {
27 | const PRESTO_USER = "X-Presto-User";
28 | const PRESTO_SOURCE = "X-Presto-Source";
29 | const PRESTO_CATALOG = "X-Presto-Catalog";
30 | const PRESTO_SCHEMA = "X-Presto-Schema";
31 | const PRESTO_TIME_ZONE = "X-Presto-Time-Zone";
32 | const PRESTO_LANGUAGE = "X-Presto-Language";
33 | const PRESTO_SESSION = "X-Presto-Session";
34 | const PRESTO_SET_SESSION = "X-Presto-Set-Session";
35 | const PRESTO_CLEAR_SESSION = "X-Presto-Clear-Session";
36 | const PRESTO_PREPARED_STATEMENT = "X-Presto-Prepared-Statement";
37 | const PRESTO_ADDED_PREPARE = "X-Presto-Added-Prepare";
38 | const PRESTO_DEALLOCATED_PREPARE = "X-Presto-Deallocated-Prepare";
39 | const PRESTO_TRANSACTION_ID = "X-Presto-Transaction-Id";
40 | const PRESTO_STARTED_TRANSACTION_ID = "X-Presto-Started-Transaction-Id";
41 | const PRESTO_CLEAR_TRANSACTION_ID = "X-Presto-Clear-Transaction-Id";
42 | const PRESTO_CLIENT_INFO = "X-Presto-Client-Info";
43 | const PRESTO_CURRENT_STATE = "X-Presto-Current-State";
44 | const PRESTO_MAX_WAIT = "X-Presto-Max-Wait";
45 | const PRESTO_MAX_SIZE = "X-Presto-Max-Size";
46 | const PRESTO_TASK_INSTANCE_ID = "X-Presto-Task-Instance-Id";
47 | const PRESTO_PAGE_TOKEN = "X-Presto-Page-Sequence-Id";
48 | const PRESTO_PAGE_NEXT_TOKEN = "X-Presto-Page-End-Sequence-Id";
49 | const PRESTO_BUFFER_COMPLETE = "X-Presto-Buffer-Complete";
50 |
51 | /** library version */
52 | const VERSION = '0.1.0';
53 | const PRESTO_SOURCE_VALUE = 'PrestoClient';
54 |
55 | private function __construct()
56 | {
57 | //
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/QueryError.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | final class QueryError
26 | {
27 | /** @var string */
28 | private $message = '';
29 |
30 | /** @var string */
31 | private $sqlState = '';
32 |
33 | /** @var int */
34 | private $errorCode;
35 |
36 | /** @var string */
37 | private $errorName;
38 |
39 | /** @var string */
40 | private $errorType;
41 |
42 | /** @var \stdClass */
43 | private $failureInfo;
44 |
45 | /**
46 | * QueryError constructor.
47 | *
48 | * @param \stdClass $jsonContent
49 | */
50 | public function __construct(\stdClass $jsonContent)
51 | {
52 | $this->message = strval($jsonContent->message);
53 | $this->sqlState = $jsonContent->sqlState ?? '';
54 | $this->errorCode = intval($jsonContent->errorCode);
55 | $this->errorName = strval($jsonContent->errorName);
56 | $this->errorType = strval($jsonContent->errorType);
57 | $this->failureInfo = $jsonContent->failureInfo;
58 | }
59 |
60 | /**
61 | * @return string
62 | */
63 | public function getMessage(): string
64 | {
65 | return $this->message;
66 | }
67 |
68 | /**
69 | * @return string
70 | */
71 | public function getSqlState(): string
72 | {
73 | return $this->sqlState;
74 | }
75 |
76 | /**
77 | * @return int
78 | */
79 | public function getErrorCode(): int
80 | {
81 | return $this->errorCode;
82 | }
83 |
84 | /**
85 | * @return string
86 | */
87 | public function getErrorName(): string
88 | {
89 | return $this->errorName;
90 | }
91 |
92 | /**
93 | * @return string
94 | */
95 | public function getErrorType(): string
96 | {
97 | return $this->errorType;
98 | }
99 |
100 | /**
101 | * @return \stdClass
102 | */
103 | public function getFailureInfo(): \stdClass
104 | {
105 | return $this->failureInfo;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/QueryResult.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | final class QueryResult
26 | {
27 | /** @var string */
28 | private $id;
29 |
30 | /** @var string */
31 | private $infoUri;
32 |
33 | /** @var string */
34 | private $partialCancelUri;
35 |
36 | /** @var string */
37 | private $nextUri;
38 |
39 | /** @var \stdClass[] */
40 | private $columns = [];
41 |
42 | /** @var array */
43 | private $data = [];
44 |
45 | /** @var StatementStats|null */
46 | private $stats;
47 |
48 | /** @var QueryError|null */
49 | private $error;
50 |
51 | /**
52 | * QueryResult constructor.
53 | *
54 | * @param string $content
55 | */
56 | public function set(string $content)
57 | {
58 | $parsed = $this->parseContent($content);
59 | $this->id = $parsed->id;
60 | $this->infoUri = $parsed->infoUri;
61 | $this->partialCancelUri = $parsed->partialCancelUri ?? null;
62 | $this->nextUri = $parsed->nextUri ?? null;
63 | $this->columns = [];
64 | if (isset($parsed->columns)) {
65 | $this->columnTransfer($parsed->columns);
66 | }
67 | $this->data = $parsed->data ?? [];
68 | $this->stats = isset($parsed->stats) ? $this->statsTransfer($parsed->stats) : null;
69 | $this->error = isset($parsed->error) ? $this->errorTransfer($parsed->error) : null;
70 | }
71 |
72 | /**
73 | * @return string|null
74 | */
75 | public function getId()
76 | {
77 | return $this->id;
78 | }
79 |
80 | /**
81 | * @return string|null
82 | */
83 | public function getInfoUri()
84 | {
85 | return $this->infoUri;
86 | }
87 |
88 | /**
89 | * @return string|null
90 | */
91 | public function getNextUri()
92 | {
93 | return $this->nextUri;
94 | }
95 |
96 | /**
97 | * @return QueryError|null
98 | */
99 | public function getError()
100 | {
101 | return $this->error;
102 | }
103 |
104 | /**
105 | * @return string|null
106 | */
107 | public function getPartialCancelUri()
108 | {
109 | return $this->partialCancelUri;
110 | }
111 |
112 | /**
113 | * @return \Generator
114 | */
115 | public function yieldData(): \Generator
116 | {
117 | if (!count($this->data)) {
118 | yield;
119 | }
120 | $column = $this->getColumns();
121 | $columnCount = count($column);
122 | foreach ($this->data as $data) {
123 | $fixData = new FixData();
124 | for ($i = 0; $i < $columnCount; $i++) {
125 | $fixData->add($column[$i]->getName(), $data[$i]);
126 | }
127 | yield $fixData;
128 | }
129 | }
130 |
131 | /**
132 | * @return \Generator
133 | */
134 | public function yieldDataArray(): \Generator
135 | {
136 | if (!count($this->data)) {
137 | yield;
138 | }
139 | $columns = array_map(function (Column $item) {
140 | return $item->getName();
141 | }, $this->getColumns());
142 | foreach ($this->data as $data) {
143 | yield array_combine($columns, $data);
144 | }
145 | }
146 |
147 | /**
148 | * @param string $fetchClassName
149 | *
150 | * @return \Generator
151 | */
152 | public function yieldObject(string $fetchClassName)
153 | {
154 | if (!count($this->data)) {
155 | yield;
156 | }
157 | $column = $this->getColumns();
158 | $columnCount = count($column);
159 | foreach ($this->data as $data) {
160 | $reflectionClass = new \ReflectionClass($fetchClassName);
161 | $newInstance = $reflectionClass->newInstanceWithoutConstructor();
162 | for ($i = 0; $i < $columnCount; $i++) {
163 | if ($reflectionClass->hasProperty($column[$i]->getName())) {
164 | $property = $reflectionClass->getProperty($column[$i]->getName());
165 | $property->setAccessible(true);
166 | $property->setValue($newInstance, $data[$i]);
167 | }
168 | }
169 | yield $newInstance;
170 | }
171 | }
172 |
173 | /**
174 | * @param string $content
175 | *
176 | * @return \stdClass
177 | */
178 | private function parseContent(string $content): \stdClass
179 | {
180 | $parsed = json_decode($content);
181 | if ($parsed === null && json_last_error() !== JSON_ERROR_NONE) {
182 | throw new \RuntimeException;
183 | }
184 |
185 | return $parsed;
186 | }
187 |
188 | /**
189 | * @param \stdClass $jsonContent
190 | *
191 | * @return StatementStats
192 | */
193 | private function statsTransfer(\stdClass $jsonContent): StatementStats
194 | {
195 | return new StatementStats($jsonContent);
196 | }
197 |
198 | /**
199 | * @param \stdClass $jsonContent
200 | *
201 | * @return QueryError
202 | */
203 | private function errorTransfer(\stdClass $jsonContent): QueryError
204 | {
205 | return new QueryError($jsonContent);
206 | }
207 |
208 | /**
209 | * @param array $columns
210 | */
211 | private function columnTransfer(array $columns)
212 | {
213 | foreach ($columns as $column) {
214 | $this->columns[] = new Column($column);
215 | }
216 | }
217 |
218 | /**
219 | * @return StatementStats|null
220 | */
221 | public function getStats()
222 | {
223 | return $this->stats;
224 | }
225 |
226 | /**
227 | * @return Column[]
228 | */
229 | public function getColumns(): array
230 | {
231 | return $this->columns;
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/src/ResultsSession.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | class ResultsSession
26 | {
27 | /** @var QueryResult[] */
28 | private $results = [];
29 |
30 | /** @var StatementClient */
31 | private $prestoClient;
32 |
33 | /** @var int */
34 | private $timeout = 500000;
35 |
36 | /** @var bool */
37 | private $debug = false;
38 |
39 | /**
40 | * @param StatementClient $prestoClient
41 | * @param int $timeout
42 | * @param bool $debug
43 | */
44 | public function __construct(StatementClient $prestoClient, int $timeout = 500000, bool $debug = false)
45 | {
46 | $this->prestoClient = $prestoClient;
47 | $this->timeout = $timeout;
48 | $this->debug = $debug;
49 | }
50 |
51 | /**
52 | * @return ResultsSession
53 | */
54 | public function execute(): ResultsSession
55 | {
56 | $this->prestoClient->execute($this->timeout, $this->debug);
57 |
58 | return $this;
59 | }
60 |
61 | /**
62 | * @return \Generator
63 | */
64 | public function yieldResults(): \Generator
65 | {
66 | while ($this->prestoClient->isValid()) {
67 | yield $this->prestoClient->current();
68 | $this->prestoClient->advance();
69 | }
70 | }
71 |
72 | /**
73 | * @return array
74 | */
75 | public function getResults(): array
76 | {
77 | while ($this->prestoClient->isValid()) {
78 | $this->addResults($this->prestoClient->current());
79 | $this->prestoClient->advance();
80 | }
81 |
82 | return $this->results;
83 | }
84 |
85 | /**
86 | * @param QueryResult $queryResult
87 | */
88 | private function addResults(QueryResult $queryResult)
89 | {
90 | $this->results[] = $queryResult;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/Session/AbstractKeyValueStorage.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | abstract class AbstractKeyValueStorage
26 | {
27 | /** @var string */
28 | private $key;
29 |
30 | /** @var string */
31 | private $value;
32 |
33 | /**
34 | * @param string $key
35 | * @param string $value
36 | */
37 | public function __construct(string $key, string $value)
38 | {
39 | $this->key = $key;
40 | $this->value = $value;
41 | }
42 |
43 | /**
44 | * @return string
45 | */
46 | public function getKey(): string
47 | {
48 | return $this->key;
49 | }
50 |
51 | /**
52 | * @return string
53 | */
54 | public function getValue(): string
55 | {
56 | return $this->value;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Session/PreparedStatement.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | final class PreparedStatement extends AbstractKeyValueStorage
26 | {
27 | }
28 |
--------------------------------------------------------------------------------
/src/Session/Property.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | final class Property extends AbstractKeyValueStorage
26 | {
27 | }
28 |
--------------------------------------------------------------------------------
/src/StatementClient.php:
--------------------------------------------------------------------------------
1 |
38 | */
39 | class StatementClient
40 | {
41 | const STATEMENT_URI = '/v1/statement';
42 |
43 | /** @var ClientInterface */
44 | private $client;
45 |
46 | /** @var ClientSession */
47 | private $session;
48 |
49 | /** @var QueryResult */
50 | protected $queryResult;
51 |
52 | /** @var array */
53 | protected $headers = [];
54 |
55 | /** @var string */
56 | protected $query;
57 |
58 | /** @var string */
59 | protected $nextUri;
60 |
61 | /** @var bool */
62 | private $gone = false;
63 |
64 | /** @var bool */
65 | private $valid = true;
66 |
67 | /** @var bool */
68 | private $closed = false;
69 |
70 | /** @var bool */
71 | private $fulfilled = false;
72 |
73 | /** @var int */
74 | protected $nanoseconds = 5000000000;
75 |
76 | /**
77 | * PrestoClient constructor.
78 | *
79 | * @param ClientSession $session
80 | * @param string $query
81 | * @param ClientInterface|null $client
82 | */
83 | public function __construct(ClientSession $session, string $query, ClientInterface $client = null)
84 | {
85 | $this->session = $session;
86 | $this->query = $query;
87 | $this->client = (is_null($client)) ? new Client : $client;
88 | $this->queryResult = new QueryResult();
89 | $this->prepareRequest();
90 | }
91 |
92 | private function prepareRequest()
93 | {
94 | $this->headers = array_merge(
95 | [
96 | PrestoHeaders::PRESTO_USER => $this->session->getUser(),
97 | 'User-Agent' => $this->session->getSource() . '/' . PrestoHeaders::VERSION
98 | ],
99 | $this->session->getHeader()
100 | );
101 | }
102 |
103 | /**
104 | * @param Request $request
105 | *
106 | * @return Request
107 | */
108 | protected function buildQueryRequest(Request $request): Request
109 | {
110 | $sessionTransaction = $this->session->getTransactionId();
111 | $transactionId = is_null($sessionTransaction) ? 'NONE' : $sessionTransaction->toString();
112 | $request = $request->withAddedHeader(PrestoHeaders::PRESTO_CATALOG, $this->session->getCatalog())
113 | ->withAddedHeader(PrestoHeaders::PRESTO_SCHEMA, $this->session->getSchema())
114 | ->withAddedHeader(PrestoHeaders::PRESTO_SOURCE, $this->session->getSource())
115 | ->withAddedHeader(PrestoHeaders::PRESTO_TRANSACTION_ID, $transactionId);
116 | $sessionProperty = $this->session->getProperty();
117 | if (count($sessionProperty)) {
118 | $sessions = [];
119 | /** @var Property $property */
120 | foreach ($sessionProperty as $property) {
121 | $sessions[] = $property->getKey() . '=' . $property->getValue();
122 | }
123 | $request = $request->withAddedHeader(
124 | PrestoHeaders::PRESTO_SESSION,
125 | implode(',', $sessions)
126 | );
127 | }
128 | $preparedStatements = $this->session->getPreparedStatement();
129 | if (count($preparedStatements)) {
130 | $statements = [];
131 | foreach ($preparedStatements as $preparedStatement) {
132 | $statements[] = urlencode($preparedStatement->getKey())
133 | . '=' . urlencode($preparedStatement->getValue());
134 | }
135 | $request = $request->withAddedHeader(
136 | PrestoHeaders::PRESTO_PREPARED_STATEMENT,
137 | implode(',', $statements)
138 | );
139 | }
140 |
141 | return $request;
142 | }
143 |
144 | /**
145 | * @param int $timeout
146 | * @param bool $debug
147 | *
148 | * @return void
149 | * @throws QueryErrorException
150 | */
151 | public function execute(int $timeout = 500000, bool $debug = false)
152 | {
153 | $normalize = UriNormalizer::normalize(
154 | new Uri($this->session->getHost() . StatementClient::STATEMENT_URI),
155 | UriNormalizer::REMOVE_DUPLICATE_SLASHES
156 | );
157 | $request = new Request(RequestMethodInterface::METHOD_POST, $normalize, $this->headers);
158 | try {
159 | $response = $this->client->send($this->buildQueryRequest($request), [
160 | 'timeout' => $timeout,
161 | 'body' => $this->query,
162 | 'debug' => $debug,
163 | ]);
164 | if ($response->getStatusCode() === StatusCodeInterface::STATUS_OK) {
165 | $this->queryResult->set($response->getBody()->getContents());
166 | }
167 | } catch (ClientException $e) {
168 | throw new QueryErrorException($e->getMessage(), $e->getCode(), $e);
169 | }
170 | }
171 |
172 | /**
173 | * @return QueryResult
174 | * @throws QueryErrorException
175 | */
176 | public function current(): QueryResult
177 | {
178 | return $this->queryResult;
179 | }
180 |
181 | /**
182 | * @return bool
183 | */
184 | public function advance(): bool
185 | {
186 | $nextUri = $this->current()->getNextUri();
187 | if (is_null($nextUri) || $this->isClosed()) {
188 | $this->valid = false;
189 |
190 | return false;
191 | }
192 | $this->prepareRequest();
193 |
194 | return $this->detectResponse($nextUri);
195 | }
196 |
197 | /**
198 | * @param int $timeout
199 | * @param bool $debug
200 | *
201 | * @return bool
202 | */
203 | public function cancelLeafStage(int $timeout = 500000, bool $debug = false): bool
204 | {
205 | if (!$this->isClosed()) {
206 | $cancelUri = $this->current()->getPartialCancelUri();
207 | if (is_null($cancelUri)) {
208 | return false;
209 | }
210 | $promise = $this->client->deleteAsync($cancelUri, [
211 | 'timeout' => $timeout,
212 | 'debug' => $debug,
213 | ]);
214 | $promise->then(function (ResponseInterface $response) {
215 | $this->fulfilled = (StatusCodeInterface::STATUS_NO_CONTENT === $response->getStatusCode());
216 | }, function (RequestException $e) {
217 | throw new RequestFailedException($e->getMessage(), $e->getCode(), $e);
218 | });
219 | $promise->wait();
220 | }
221 |
222 | return $this->fulfilled;
223 | }
224 |
225 | /**
226 | * @param int $nanoseconds
227 | */
228 | public function setNanoseconds(int $nanoseconds)
229 | {
230 | $this->nanoseconds = $nanoseconds;
231 | }
232 |
233 | /**
234 | * @return string
235 | */
236 | public function getQuery(): string
237 | {
238 | return $this->query;
239 | }
240 |
241 | /**
242 | * @return bool
243 | */
244 | public function isFailed(): bool
245 | {
246 | return $this->queryResult->getError() !== null;
247 | }
248 |
249 | /**
250 | * @return bool
251 | */
252 | public function isValid(): bool
253 | {
254 | return $this->valid && (!$this->isGone()) && (!$this->isClosed());
255 | }
256 |
257 | /**
258 | * @return bool
259 | */
260 | public function isGone(): bool
261 | {
262 | return $this->gone;
263 | }
264 |
265 | /**
266 | * @return bool
267 | */
268 | public function isClosed(): bool
269 | {
270 | return $this->closed;
271 | }
272 |
273 | /**
274 | * close
275 | * HTTP method DELETE
276 | */
277 | public function close()
278 | {
279 | $uri = $this->current()->getNextUri();
280 | if (!is_null($uri)) {
281 | $this->client->deleteAsync($uri)->wait();
282 | }
283 | $this->closed = true;
284 | }
285 |
286 | /**
287 | * @param string $message
288 | * @param string $uri
289 | * @param ResponseInterface|null $response
290 | *
291 | * @return RequestFailedException
292 | */
293 | private function requestFailedException(
294 | string $message,
295 | string $uri,
296 | ResponseInterface $response = null
297 | ): RequestFailedException {
298 | $this->gone = true;
299 | if ($response) {
300 | if (!$response->getBody()->getSize()) {
301 | return new RequestFailedException(
302 | sprintf(
303 | "Error %s at %s returned an invalid response: %s [Error: %s]",
304 | $message,
305 | $uri,
306 | $response->getStatusCode(),
307 | $response->getBody()->getContents()
308 | )
309 | );
310 | }
311 |
312 | return new RequestFailedException(
313 | sprintf(
314 | "Error %s at %s returned %s: %s",
315 | $message,
316 | $uri,
317 | $response->getStatusCode(),
318 | $response->getBody()->getContents()
319 | )
320 | );
321 | }
322 |
323 | return new RequestFailedException('server error.');
324 | }
325 |
326 | /**
327 | * @param string $nextUri
328 | *
329 | * @return bool
330 | */
331 | private function detectResponse(string $nextUri): bool
332 | {
333 | $start = microtime(true);
334 | $cause = null;
335 | $attempts = 0;
336 | do {
337 | if ($attempts > 0) {
338 | usleep($attempts * 100);
339 | }
340 | $attempts++;
341 | try {
342 | $response = $this->client->get($nextUri, ['headers' => $this->headers]);
343 | if ($response->getStatusCode() === StatusCodeInterface::STATUS_OK) {
344 | $this->queryResult->set($response->getBody()->getContents());
345 |
346 | return true;
347 | }
348 | } catch (ClientException $e) {
349 | $cause = $e;
350 | if ($e->getCode() != StatusCodeInterface::STATUS_SERVICE_UNAVAILABLE) {
351 | throw $this->requestFailedException("fetching next", $nextUri, $e->getResponse());
352 | }
353 | }
354 | } while (((microtime(true) - $start) < $this->nanoseconds) && !$this->isClosed());
355 |
356 | $this->gone = true;
357 | throw new \RuntimeException('Error fetching next', 0, $cause);
358 | }
359 | }
360 |
--------------------------------------------------------------------------------
/src/StatementStats.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | final class StatementStats
26 | {
27 | /** @var string */
28 | private $state = '';
29 |
30 | /** @var bool */
31 | private $queued;
32 |
33 | /** @var bool */
34 | private $scheduled;
35 |
36 | /** @var int */
37 | private $nodes;
38 |
39 | /** @var int */
40 | private $totalSplits;
41 |
42 | /** @var int */
43 | private $queuedSplits;
44 |
45 | /** @var int */
46 | private $runningSplits;
47 |
48 | /** @var int */
49 | private $completedSplits;
50 |
51 | /** @var int */
52 | private $userTimeMillis;
53 |
54 | /** @var int */
55 | private $cpuTimeMillis;
56 |
57 | /** @var int */
58 | private $wallTimeMillis;
59 |
60 | /** @var int */
61 | private $processedRows;
62 |
63 | /** @var int */
64 | private $processedBytes;
65 |
66 | /** @var \stdClass */
67 | private $rootStage;
68 |
69 | /** @var string[] */
70 | private $primitiveCasts = [
71 | 'state' => 'strval',
72 | 'queued' => 'boolval',
73 | 'scheduled' => 'boolval',
74 | 'nodes' => 'intval',
75 | 'totalSplits' => 'intval',
76 | 'queuedSplits' => 'intval',
77 | 'runningSplits' => 'intval',
78 | 'completedSplits' => 'intval',
79 | 'userTimeMillis' => 'intval',
80 | 'cpuTimeMillis' => 'intval',
81 | 'wallTimeMillis' => 'intval',
82 | 'processedRows' => 'intval',
83 | 'processedBytes' => 'intval',
84 | ];
85 |
86 | /**
87 | * StatementStats constructor.
88 | *
89 | * @param \stdClass $jsonContent
90 | */
91 | public function __construct(\stdClass $jsonContent)
92 | {
93 | $arrayContent = (array)$jsonContent;
94 | foreach ($arrayContent as $element => $value) {
95 | if (property_exists($this, $element)) {
96 | if (isset($this->primitiveCasts[$element])) {
97 | $castFunction = $this->primitiveCasts[$element];
98 | $this->$element = $castFunction($value);
99 | }
100 | }
101 | }
102 | if (isset($jsonContent->rootStage)) {
103 | $this->rootStage = $jsonContent->rootStage;
104 | }
105 | }
106 |
107 | /**
108 | * @return string
109 | */
110 | public function getState(): string
111 | {
112 | return $this->state;
113 | }
114 |
115 | /**
116 | * @return bool
117 | */
118 | public function isQueued(): bool
119 | {
120 | return $this->queued;
121 | }
122 |
123 | /**
124 | * @return bool
125 | */
126 | public function isScheduled(): bool
127 | {
128 | return $this->scheduled;
129 | }
130 |
131 | /**
132 | * @return int
133 | */
134 | public function getNodes(): int
135 | {
136 | return $this->nodes;
137 | }
138 |
139 | /**
140 | * @return int
141 | */
142 | public function getTotalSplits(): int
143 | {
144 | return $this->totalSplits;
145 | }
146 |
147 | /**
148 | * @return int
149 | */
150 | public function getQueuedSplits(): int
151 | {
152 | return $this->queuedSplits;
153 | }
154 |
155 | /**
156 | * @return int
157 | */
158 | public function getRunningSplits(): int
159 | {
160 | return $this->runningSplits;
161 | }
162 |
163 | /**
164 | * @return int
165 | */
166 | public function getCompletedSplits(): int
167 | {
168 | return $this->completedSplits;
169 | }
170 |
171 | /**
172 | * @return int
173 | */
174 | public function getUserTimeMillis(): int
175 | {
176 | return $this->userTimeMillis;
177 | }
178 |
179 | /**
180 | * @return int
181 | */
182 | public function getCpuTimeMillis(): int
183 | {
184 | return $this->cpuTimeMillis;
185 | }
186 |
187 | /**
188 | * @return int
189 | */
190 | public function getWallTimeMillis(): int
191 | {
192 | return $this->wallTimeMillis;
193 | }
194 |
195 | /**
196 | * @return int
197 | */
198 | public function getProcessedRows(): int
199 | {
200 | return $this->processedRows;
201 | }
202 |
203 | /**
204 | * @return int
205 | */
206 | public function getProcessedBytes(): int
207 | {
208 | return $this->processedBytes;
209 | }
210 |
211 | /**
212 | * @return \stdClass|null
213 | */
214 | public function getRootStage()
215 | {
216 | return $this->rootStage;
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/tests/ClientSessionTest.php:
--------------------------------------------------------------------------------
1 | assertSame('testing', $session->getCatalog());
18 | $this->assertSame('http://localhost', $session->getHost());
19 | $this->assertSame('PrestoClient', $session->getSource());
20 | $this->assertSame('default', $session->getSchema());
21 | $this->assertSame('presto', $session->getUser());
22 | $this->assertNull($session->getTransactionId());
23 | $this->assertCount(0, $session->getProperty());
24 | $this->assertCount(0, $session->getPreparedStatement());
25 | }
26 |
27 | public function testShouldReturnChangedSession()
28 | {
29 | $session = new ClientSession('http://localhost', 'testing');
30 | $session->setSchema('testing');
31 | $this->assertSame('testing', $session->getSchema());
32 | $session->setSource('testingPresto');
33 | $this->assertSame('testingPresto', $session->getSource());
34 | $uuid = \Ramsey\Uuid\Uuid::uuid4();
35 | $session->setTransactionId($uuid);
36 | $this->assertSame($uuid, $session->getTransactionId());
37 | $session->setUser('testing');
38 | $this->assertSame('testing', $session->getUser());
39 | $session->setProperty(new Property('testing', '1'));
40 | $this->assertCount(1, $session->getProperty());
41 | $this->assertSame('testing', $session->getProperty()[0]->getKey());
42 | $this->assertSame('1', $session->getProperty()[0]->getValue());
43 | $session->setPreparedStatement(new PreparedStatement('1', '1'));
44 | $this->assertCount(1, $session->getPreparedStatement());
45 | $this->assertSame('1', $session->getPreparedStatement()[0]->getKey());
46 | $this->assertSame('1', $session->getPreparedStatement()[0]->getValue());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/tests/LoggerClientTest.php:
--------------------------------------------------------------------------------
1 | pushHandler($testHandler);
25 | $loggerClient = new LoggerClient($logger);
26 |
27 | $client = new \Ytake\PrestoClient\StatementClient(
28 | $this->session(),
29 | 'SELECT * FROM example.hoge.fuga',
30 | $loggerClient->client($mock)
31 | );
32 | $client->execute();
33 | $records = $testHandler->getRecords();
34 | $this->assertCount(1, $records);
35 | }
36 |
37 | /**
38 | * @return ClientSession
39 | */
40 | private function session(): ClientSession
41 | {
42 | return new ClientSession('http://localhost', 'testing');
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/MockClientTrait.php:
--------------------------------------------------------------------------------
1 | HandlerStack::create($mock)]);
30 | }
31 |
32 | /**
33 | * @return Client
34 | */
35 | public function throwRequestExceptionClient(): Client
36 | {
37 | $mock = new MockHandler([
38 | new RequestException("Error Communicating with Server", new Request('GET', 'test')),
39 | ]);
40 |
41 | return new Client(['handler' => HandlerStack::create($mock)]);
42 | }
43 |
44 | /**
45 | * @return Client
46 | */
47 | public function throwClientExceptionClient(): Client
48 | {
49 | $mock = new MockHandler([
50 | new \GuzzleHttp\Exception\ClientException("Error Communicating with Server", new Request('POST', 'test')),
51 | ]);
52 |
53 | return new Client(['handler' => HandlerStack::create($mock)]);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/tests/ResultsSessionTest.php:
--------------------------------------------------------------------------------
1 | session(),
27 | 'SELECT * FROM example.hoge.fuga',
28 | new Client(['handler' => HandlerStack::create($mock)])
29 | );
30 | $resultSession = new ResultsSession($client);
31 | $result = $resultSession->execute()->getResults();
32 | $this->assertNotCount(0, $result);
33 | $this->assertContainsOnlyInstancesOf(QueryResult::class, $result);
34 | }
35 |
36 | public function testShouldReturnQueryResultGenerator()
37 | {
38 | $mock = new MockHandler([
39 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/success.json'))),
40 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/next_response.json'))),
41 | new Response(204, [], file_get_contents(realpath(__DIR__ . '/data/third_response.json'))),
42 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/fourth_response.json'))),
43 | ]);
44 | $client = new \Ytake\PrestoClient\StatementClient(
45 | $this->session(),
46 | 'SELECT * FROM example.hoge.fuga',
47 | new Client(['handler' => HandlerStack::create($mock)])
48 | );
49 | $resultSession = new ResultsSession($client);
50 | $result = $resultSession->execute()->yieldResults();
51 | $this->assertInstanceOf(\Generator::class, $result);
52 | /** @var \Ytake\PrestoClient\QueryResult $row */
53 | foreach ($result as $row) {
54 | $this->assertInstanceOf(QueryResult::class, $row);
55 | $this->assertInstanceOf(\Generator::class, $row->yieldData());
56 | foreach ($row->yieldData() as $item) {
57 | if (!is_null($item)) {
58 | $this->assertInstanceOf(\Ytake\PrestoClient\FixData::class, $item);
59 | }
60 | }
61 | }
62 | }
63 |
64 | public function testShouldReturnQueryResultWithDataArray()
65 | {
66 | $mock = new MockHandler([
67 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/success.json'))),
68 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/next_response.json'))),
69 | new Response(204, [], file_get_contents(realpath(__DIR__ . '/data/third_response.json'))),
70 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/fourth_response.json'))),
71 | ]);
72 | $client = new \Ytake\PrestoClient\StatementClient(
73 | $this->session(),
74 | 'SELECT * FROM example.hoge.fuga',
75 | new Client(['handler' => HandlerStack::create($mock)])
76 | );
77 | $resultSession = new ResultsSession($client);
78 | $result = $resultSession->execute()->yieldResults();
79 | foreach ($result as $row) {
80 | foreach ($row->yieldDataArray() as $item) {
81 | if (!is_null($item)) {
82 | $this->assertInternalType('array', $item);
83 | $this->assertArrayHasKey('test_id', $item);
84 | }
85 | }
86 | }
87 | }
88 |
89 | public function testShouldBeExpectInstance()
90 | {
91 | $mock = new MockHandler([
92 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/success.json'))),
93 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/next_response.json'))),
94 | new Response(204, [], file_get_contents(realpath(__DIR__ . '/data/third_response.json'))),
95 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/fourth_response.json'))),
96 | ]);
97 | $client = new \Ytake\PrestoClient\StatementClient(
98 | $this->session(),
99 | 'SELECT * FROM example.hoge.fuga',
100 | new Client(['handler' => HandlerStack::create($mock)])
101 | );
102 | $resultSession = new ResultsSession($client);
103 | $result = $resultSession->execute()->yieldResults();
104 | /** @var \Ytake\PrestoClient\QueryResult $row */
105 | foreach ($result as $row) {
106 | foreach ($row->yieldObject(MockResultTest::class) as $item) {
107 | if (!is_null($item)) {
108 | $this->assertInstanceOf(MockResultTest::class, $item);
109 | $this->assertSame(1, $item->testId());
110 | }
111 | }
112 | }
113 | }
114 |
115 | /**
116 | * @return ClientSession
117 | */
118 | private function session(): ClientSession
119 | {
120 | return new ClientSession('http://localhost', 'testing');
121 | }
122 | }
123 |
124 | class MockResultTest
125 | {
126 | /** @var int */
127 | private $test_id;
128 |
129 | /**
130 | * @return int
131 | */
132 | public function testId(): int
133 | {
134 | return $this->test_id;
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/tests/StatementClientTest.php:
--------------------------------------------------------------------------------
1 | session(),
30 | 'SELECT * FROM example.hoge.fuga',
31 | $this->mockClient(StatusCodeInterface::STATUS_OK)
32 | );
33 | $this->assertSame('SELECT * FROM example.hoge.fuga', $client->getQuery());
34 | $queryResult = $client->current();
35 | $this->assertInstanceOf(QueryResult::class, $queryResult);
36 | $this->assertNull($queryResult->getId());
37 | $this->assertNull($queryResult->getInfoUri());
38 | $this->assertNull($queryResult->getPartialCancelUri());
39 | $this->assertNull($queryResult->getNextUri());
40 | $this->assertNull($queryResult->getStats());
41 | $this->assertNull($queryResult->getError());
42 | $this->assertCount(0, $queryResult->getColumns());
43 | $this->assertInstanceOf(\Generator::class, $queryResult->yieldData());
44 | $this->assertFalse($client->cancelLeafStage());
45 | $this->assertFalse($client->isClosed());
46 | $this->assertFalse($client->advance());
47 | $this->assertFalse($client->isValid());
48 | $this->assertFalse($client->isGone());
49 | $this->assertFalse($client->isFailed());
50 | $client->close();
51 | $this->assertTrue($client->isClosed());
52 | }
53 |
54 | public function testShouldBeErrorQueryResult()
55 | {
56 | $error = file_get_contents(realpath(__DIR__ . '/data/error.json'));
57 | $client = new \Ytake\PrestoClient\StatementClient(
58 | $this->session(),
59 | 'SELECT * FROM example.hoge.fuga',
60 | $this->mockClient(StatusCodeInterface::STATUS_OK, $error)
61 | );
62 | $this->assertNull($client->execute());
63 | $this->assertFalse($client->advance());
64 | $queryResult = $client->current();
65 | $this->assertInstanceOf(QueryResult::class, $queryResult);
66 | $this->assertNotNull($queryResult->getId());
67 | $this->assertNotNull($queryResult->getInfoUri());
68 | $this->assertNull($queryResult->getPartialCancelUri());
69 | $this->assertNull($queryResult->getNextUri());
70 | $stats = $queryResult->getStats();
71 | $this->assertInstanceOf(StatementStats::class, $stats);
72 | $this->assertSame('FAILED', $stats->getState());
73 | $this->assertFalse($stats->isQueued());
74 | $this->assertFalse($stats->isScheduled());
75 | $this->assertSame(0, $stats->getCompletedSplits());
76 | $this->assertSame(0, $stats->getCpuTimeMillis());
77 | $this->assertSame(0, $stats->getNodes());
78 | $this->assertSame(0, $stats->getProcessedBytes());
79 | $this->assertSame(0, $stats->getProcessedRows());
80 | $this->assertSame(0, $stats->getCpuTimeMillis());
81 | $this->assertSame(0, $stats->getQueuedSplits());
82 | $this->assertSame(0, $stats->getRunningSplits());
83 | $this->assertSame(0, $stats->getCompletedSplits());
84 | $this->assertSame(0, $stats->getTotalSplits());
85 | $this->assertSame(0, $stats->getUserTimeMillis());
86 | $this->assertSame(0, $stats->getWallTimeMillis());
87 | $error = $queryResult->getError();
88 | $this->assertInstanceOf(QueryError::class, $error);
89 | $this->assertInternalType('string', $error->getMessage());
90 | $this->assertInternalType('int', $error->getErrorCode());
91 | $this->assertInternalType('string', $error->getErrorName());
92 | $this->assertInternalType('string', $error->getErrorType());
93 | $this->assertInstanceOf(\stdClass::class, $error->getFailureInfo());
94 | $this->assertInternalType('string', $error->getSqlState());
95 | }
96 |
97 | /**
98 | * @expectedException \GuzzleHttp\Exception\RequestException
99 | */
100 | public function testShouldThrowRequestException()
101 | {
102 | $client = new \Ytake\PrestoClient\StatementClient(
103 | $this->session(),
104 | 'SELECT * FROM example.hoge.fuga',
105 | $this->throwRequestExceptionClient()
106 | );
107 | $client->execute();
108 | }
109 |
110 | /**
111 | * @expectedException \Ytake\PrestoClient\Exception\QueryErrorException
112 | */
113 | public function testShouldThrowQueryErrorException()
114 | {
115 | $client = new \Ytake\PrestoClient\StatementClient(
116 | $this->session(),
117 | 'SELECT * FROM example.hoge.fuga',
118 | $this->throwClientExceptionClient()
119 | );
120 | $client->execute();
121 | }
122 |
123 | public function testFunctionalClientProperties()
124 | {
125 | $client = new \Ytake\PrestoClient\StatementClient(
126 | $this->session(),
127 | 'SELECT * FROM example.hoge.fuga',
128 | $this->mockClient(StatusCodeInterface::STATUS_OK)
129 | );
130 | $property = $this->getProtectProperty($client, 'headers');
131 | $defaultHeaders = $property->getValue($client);
132 | $this->assertArrayHasKey(PrestoHeaders::PRESTO_USER, $defaultHeaders);
133 | $this->assertArrayHasKey('User-Agent', $defaultHeaders);
134 |
135 | $session = $this->session();
136 | $session->setPreparedStatement(new PreparedStatement('testing', '1'));
137 | $session->setProperty(new Property('testing', 'testing'));
138 | $body = file_get_contents(realpath(__DIR__ . '/data/success.json'));
139 | $client = new \Ytake\PrestoClient\StatementClient(
140 | $session,
141 | 'SELECT * FROM example.hoge.fuga',
142 | $this->mockClient(StatusCodeInterface::STATUS_OK, $body)
143 | );
144 | $client->execute();
145 | $queryResult = $client->current();
146 | $this->assertInstanceOf(QueryResult::class, $queryResult);
147 | $this->assertNotNull($queryResult->getId());
148 | $this->assertNotNull($queryResult->getInfoUri());
149 | $this->assertNull($queryResult->getPartialCancelUri());
150 | $this->assertNotNull($queryResult->getNextUri());
151 | $stats = $queryResult->getStats();
152 | $this->assertInstanceOf(StatementStats::class, $stats);
153 | $this->assertSame('QUEUED', $stats->getState());
154 | $this->assertTrue($stats->isQueued());
155 | $this->assertFalse($stats->isScheduled());
156 | }
157 |
158 | public function testFunctionalStackTwo()
159 | {
160 | $mock = new MockHandler([
161 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/success.json'))),
162 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/next_response.json'))),
163 | ]);
164 | $client = new \Ytake\PrestoClient\StatementClient(
165 | $this->session(),
166 | 'SELECT * FROM example.hoge.fuga',
167 | new Client(['handler' => HandlerStack::create($mock)])
168 | );
169 | $client->execute();
170 | $this->assertTrue($client->advance());
171 | $queryResult = $client->current();
172 | $this->assertInstanceOf(\stdClass::class, $queryResult->getStats()->getRootStage());
173 | $columns = $queryResult->getColumns();
174 | $column = $columns[0];
175 | $this->assertInstanceOf(Column::class, $column);
176 | $this->assertSame('test_id', $column->getName());
177 | $this->assertSame('integer', $column->getType());
178 | $this->assertInstanceOf(\stdClass::class, $column->getTypeSignature());
179 | }
180 |
181 | public function testFunctionalStackFour()
182 | {
183 | $mock = new MockHandler([
184 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/success.json'))),
185 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/next_response.json'))),
186 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/third_response.json'))),
187 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/fourth_response.json'))),
188 | ]);
189 | $client = new \Ytake\PrestoClient\StatementClient(
190 | $this->session(),
191 | 'SELECT * FROM example.hoge.fuga',
192 | new Client(['handler' => HandlerStack::create($mock)])
193 | );
194 | $client->execute();
195 | $this->assertTrue($client->advance());
196 | $queryResult = $client->current();
197 | $this->assertInstanceOf(\stdClass::class, $queryResult->getStats()->getRootStage());
198 | $columns = $queryResult->getColumns();
199 | $column = $columns[0];
200 | $this->assertInstanceOf(Column::class, $column);
201 | $this->assertSame('test_id', $column->getName());
202 | $this->assertSame('integer', $column->getType());
203 | $this->assertInstanceOf(\stdClass::class, $column->getTypeSignature());
204 | $this->assertTrue($client->advance());
205 | $this->assertTrue($client->advance());
206 | $queryResult = $client->current();
207 | $this->assertInstanceOf(\Generator::class, $queryResult->yieldData());
208 | /** @var FixData[] $array */
209 | $array = iterator_to_array($queryResult->yieldData());
210 | $this->assertCount(1, $array);
211 | $this->assertContainsOnly(FixData::class, $array);
212 | $this->assertSame(1, $array[0]['test_id']);
213 | $this->assertSame(1, $array[0]->test_id);
214 | $this->assertSame(1, $array[0]->offsetGet('test_id'));
215 | $this->assertTrue($array[0]->offsetExists('test_id'));
216 | $array[0]->offsetUnset('test_id');
217 | $this->assertNull($array[0]->offsetGet('test_id'));
218 | $array[0]->offsetSet('test_id', 12);
219 | $this->assertSame(12, $array[0]->offsetGet('test_id'));
220 | $this->assertFalse($client->advance());
221 | }
222 |
223 | public function testShouldBeCancel()
224 | {
225 | $mock = new MockHandler([
226 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/success.json'))),
227 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/next_response.json'))),
228 | new Response(204, [], file_get_contents(realpath(__DIR__ . '/data/third_response.json'))),
229 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/fourth_response.json'))),
230 | ]);
231 | $client = new \Ytake\PrestoClient\StatementClient(
232 | $this->session(),
233 | 'SELECT * FROM example.hoge.fuga',
234 | new Client(['handler' => HandlerStack::create($mock)])
235 | );
236 | $client->execute();
237 | $this->assertTrue($client->advance());
238 | $this->assertTrue($client->cancelLeafStage());
239 | $this->assertTrue($client->advance());
240 | $this->assertFalse($client->advance());
241 | }
242 |
243 | /**
244 | * @expectedException \Ytake\PrestoClient\Exception\RequestFailedException
245 | */
246 | public function testShouldThrowRequestFailedException()
247 | {
248 | $mock = new MockHandler([
249 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/success.json'))),
250 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/success.json'))),
251 | new Response(404, [], file_get_contents(realpath(__DIR__ . '/data/next_response.json'))),
252 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/success.json'))),
253 | new Response(200, [], file_get_contents(realpath(__DIR__ . '/data/success.json'))),
254 | ]);
255 | $client = new \Ytake\PrestoClient\StatementClient(
256 | $this->session(),
257 | 'SELECT * FROM example.hoge.fuga',
258 | new Client(['handler' => HandlerStack::create($mock)])
259 | );
260 | $client->execute();
261 | $client->advance();
262 | $client->advance();
263 | }
264 |
265 | /**
266 | * @return ClientSession
267 | */
268 | private function session(): ClientSession
269 | {
270 | return new ClientSession('http://localhost', 'testing');
271 | }
272 | }
273 |
--------------------------------------------------------------------------------
/tests/TestReflectionTrait.php:
--------------------------------------------------------------------------------
1 | getProperty($name);
19 | $property->setAccessible(true);
20 |
21 | return $property;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tests/build/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/tests/data/error.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "20170618_093618_00058_3ytfr",
3 | "infoUri": "http://localhost:8080/query.html?20170618_093618_00058_3ytfr",
4 | "stats": {
5 | "state": "FAILED",
6 | "queued": false,
7 | "scheduled": false,
8 | "nodes": 0,
9 | "totalSplits": 0,
10 | "queuedSplits": 0,
11 | "runningSplits": 0,
12 | "completedSplits": 0,
13 | "userTimeMillis": 0,
14 | "cpuTimeMillis": 0,
15 | "wallTimeMillis": 0,
16 | "processedRows": 0,
17 | "processedBytes": 0
18 | },
19 | "error": {
20 | "message": "Unknown session property session_variable_2",
21 | "errorCode": 14,
22 | "errorName": "INVALID_SESSION_PROPERTY",
23 | "errorType": "USER_ERROR",
24 | "failureInfo": {
25 | "type": "com.facebook.presto.spi.PrestoException",
26 | "message": "Unknown session property session_variable_2",
27 | "suppressed": [],
28 | "stack": [
29 | "com.facebook.presto.metadata.SessionPropertyManager.lambda$validateSystemSessionProperty$2(SessionPropertyManager.java:190)",
30 | "java.util.Optional.orElseThrow(Optional.java:290)",
31 | "com.facebook.presto.metadata.SessionPropertyManager.validateSystemSessionProperty(SessionPropertyManager.java:190)",
32 | "com.facebook.presto.Session.beginTransactionId(Session.java:250)",
33 | "com.facebook.presto.execution.QueryStateMachine.beginWithTicker(QueryStateMachine.java:188)",
34 | "com.facebook.presto.execution.QueryStateMachine.begin(QueryStateMachine.java:166)",
35 | "com.facebook.presto.execution.SqlQueryExecution.\u003Cinit\u003E(SqlQueryExecution.java:167)",
36 | "com.facebook.presto.execution.SqlQueryExecution$SqlQueryExecutionFactory.createQueryExecution(SqlQueryExecution.java:641)",
37 | "com.facebook.presto.execution.SqlQueryExecution$SqlQueryExecutionFactory.createQueryExecution(SqlQueryExecution.java:563)",
38 | "com.facebook.presto.execution.SqlQueryManager.createQuery(SqlQueryManager.java:366)",
39 | "com.facebook.presto.server.StatementResource$Query.\u003Cinit\u003E(StatementResource.java:329)",
40 | "com.facebook.presto.server.StatementResource.createQuery(StatementResource.java:173)",
41 | "sun.reflect.GeneratedMethodAccessor579.invoke(Unknown Source)",
42 | "sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
43 | "java.lang.reflect.Method.invoke(Method.java:498)",
44 | "org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)",
45 | "org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)",
46 | "org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)",
47 | "org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)",
48 | "org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)",
49 | "org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)",
50 | "org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)",
51 | "org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)",
52 | "org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)",
53 | "org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)",
54 | "org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)",
55 | "org.glassfish.jersey.internal.Errors.process(Errors.java:315)",
56 | "org.glassfish.jersey.internal.Errors.process(Errors.java:297)",
57 | "org.glassfish.jersey.internal.Errors.process(Errors.java:267)",
58 | "org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)",
59 | "org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)",
60 | "org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)",
61 | "org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)",
62 | "org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)",
63 | "org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)",
64 | "org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)",
65 | "org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)",
66 | "org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:845)",
67 | "org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1689)",
68 | "io.airlift.http.server.TraceTokenFilter.doFilter(TraceTokenFilter.java:63)",
69 | "org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1676)",
70 | "io.airlift.http.server.TimingFilter.doFilter(TimingFilter.java:52)",
71 | "org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1676)",
72 | "org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:581)",
73 | "org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)",
74 | "org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:395)",
75 | "org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1182)",
76 | "org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:511)",
77 | "org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1112)",
78 | "org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)",
79 | "org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:119)",
80 | "org.eclipse.jetty.server.handler.StatisticsHandler.handle(StatisticsHandler.java:169)",
81 | "org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:52)",
82 | "org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)",
83 | "org.eclipse.jetty.server.Server.handle(Server.java:523)",
84 | "org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:320)",
85 | "org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)",
86 | "org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:273)",
87 | "org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)",
88 | "org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:93)",
89 | "org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.executeProduceConsume(ExecuteProduceConsume.java:303)",
90 | "org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceConsume(ExecuteProduceConsume.java:148)",
91 | "org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:136)",
92 | "org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:671)",
93 | "org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:589)",
94 | "java.lang.Thread.run(Thread.java:748)"
95 | ]
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/tests/data/fourth_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "20170618_155510_00077_3ytfr",
3 | "infoUri": "http://localhost:8080/query.html?20170618_155510_00077_3ytfr",
4 | "partialCancelUri": "http://localhost:8080/v1/stage/20170618_155510_00077_3ytfr.1",
5 | "columns": [
6 | {
7 | "name": "test_id",
8 | "type": "integer",
9 | "typeSignature": {
10 | "rawType": "integer",
11 | "typeArguments": [],
12 | "literalArguments": [],
13 | "arguments": []
14 | }
15 | }
16 | ],
17 | "data": [
18 | [
19 | 1
20 | ]
21 | ],
22 | "stats": {
23 | "state": "RUNNING",
24 | "queued": false,
25 | "scheduled": true,
26 | "nodes": 1,
27 | "totalSplits": 18,
28 | "queuedSplits": 16,
29 | "runningSplits": 1,
30 | "completedSplits": 0,
31 | "userTimeMillis": 0,
32 | "cpuTimeMillis": 0,
33 | "wallTimeMillis": 0,
34 | "processedRows": 0,
35 | "processedBytes": 0,
36 | "rootStage": {
37 | "stageId": "0",
38 | "state": "RUNNING",
39 | "done": false,
40 | "nodes": 1,
41 | "totalSplits": 17,
42 | "queuedSplits": 16,
43 | "runningSplits": 0,
44 | "completedSplits": 0,
45 | "userTimeMillis": 0,
46 | "cpuTimeMillis": 0,
47 | "wallTimeMillis": 0,
48 | "processedRows": 0,
49 | "processedBytes": 0,
50 | "subStages": [
51 | {
52 | "stageId": "1",
53 | "state": "RUNNING",
54 | "done": false,
55 | "nodes": 1,
56 | "totalSplits": 1,
57 | "queuedSplits": 0,
58 | "runningSplits": 1,
59 | "completedSplits": 0,
60 | "userTimeMillis": 0,
61 | "cpuTimeMillis": 0,
62 | "wallTimeMillis": 0,
63 | "processedRows": 0,
64 | "processedBytes": 0,
65 | "subStages": []
66 | }
67 | ]
68 | },
69 | "progressPercentage": 0.0
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/tests/data/next_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "20170618_151811_00066_3ytfr",
3 | "infoUri": "http://localhost:8080/query.html?20170618_151811_00066_3ytfr",
4 | "partialCancelUri": "http://localhost:8080/v1/stage/20170618_151811_00066_3ytfr.1",
5 | "nextUri": "http://localhost:8080/v1/statement/20170618_151811_00066_3ytfr/2",
6 | "columns": [
7 | {
8 | "name": "test_id",
9 | "type": "integer",
10 | "typeSignature": {
11 | "rawType": "integer",
12 | "typeArguments": [],
13 | "literalArguments": [],
14 | "arguments": []
15 | }
16 | }
17 | ],
18 | "stats": {
19 | "state": "RUNNING",
20 | "queued": false,
21 | "scheduled": false,
22 | "nodes": 1,
23 | "totalSplits": 0,
24 | "queuedSplits": 0,
25 | "runningSplits": 0,
26 | "completedSplits": 0,
27 | "userTimeMillis": 0,
28 | "cpuTimeMillis": 0,
29 | "wallTimeMillis": 0,
30 | "processedRows": 0,
31 | "processedBytes": 0,
32 | "rootStage": {
33 | "stageId": "0",
34 | "state": "PLANNED",
35 | "done": false,
36 | "nodes": 0,
37 | "totalSplits": 0,
38 | "queuedSplits": 0,
39 | "runningSplits": 0,
40 | "completedSplits": 0,
41 | "userTimeMillis": 0,
42 | "cpuTimeMillis": 0,
43 | "wallTimeMillis": 0,
44 | "processedRows": 0,
45 | "processedBytes": 0,
46 | "subStages": [
47 | {
48 | "stageId": "1",
49 | "state": "SCHEDULED",
50 | "done": false,
51 | "nodes": 1,
52 | "totalSplits": 0,
53 | "queuedSplits": 0,
54 | "runningSplits": 0,
55 | "completedSplits": 0,
56 | "userTimeMillis": 0,
57 | "cpuTimeMillis": 0,
58 | "wallTimeMillis": 0,
59 | "processedRows": 0,
60 | "processedBytes": 0,
61 | "subStages": []
62 | }
63 | ]
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/tests/data/success.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "20170618_151959_00067_3ytfr",
3 | "infoUri": "http://localhost:8080/query.html?20170618_151959_00067_3ytfr",
4 | "nextUri": "http://localhost:8080/v1/statement/20170618_151959_00067_3ytfr/1",
5 | "stats": {
6 | "state": "QUEUED",
7 | "queued": true,
8 | "scheduled": false,
9 | "nodes": 0,
10 | "totalSplits": 0,
11 | "queuedSplits": 0,
12 | "runningSplits": 0,
13 | "completedSplits": 0,
14 | "userTimeMillis": 0,
15 | "cpuTimeMillis": 0,
16 | "wallTimeMillis": 0,
17 | "processedRows": 0,
18 | "processedBytes": 0
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tests/data/third_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "20170618_154732_00069_3ytfr",
3 | "infoUri": "http://localhost:8080/query.html?20170618_154732_00069_3ytfr",
4 | "partialCancelUri": "http://localhost:8080/v1/stage/20170618_154732_00069_3ytfr.1",
5 | "nextUri": "http://localhost:8080/v1/statement/20170618_154732_00069_3ytfr/3",
6 | "columns": [
7 | {
8 | "name": "test_id",
9 | "type": "integer",
10 | "typeSignature": {
11 | "rawType": "integer",
12 | "typeArguments": [],
13 | "literalArguments": [],
14 | "arguments": []
15 | }
16 | }
17 | ],
18 | "stats": {
19 | "state": "RUNNING",
20 | "queued": false,
21 | "scheduled": false,
22 | "nodes": 1,
23 | "totalSplits": 0,
24 | "queuedSplits": 0,
25 | "runningSplits": 0,
26 | "completedSplits": 0,
27 | "userTimeMillis": 0,
28 | "cpuTimeMillis": 0,
29 | "wallTimeMillis": 0,
30 | "processedRows": 0,
31 | "processedBytes": 0,
32 | "rootStage": {
33 | "stageId": "0",
34 | "state": "SCHEDULING",
35 | "done": false,
36 | "nodes": 1,
37 | "totalSplits": 0,
38 | "queuedSplits": 0,
39 | "runningSplits": 0,
40 | "completedSplits": 0,
41 | "userTimeMillis": 0,
42 | "cpuTimeMillis": 0,
43 | "wallTimeMillis": 0,
44 | "processedRows": 0,
45 | "processedBytes": 0,
46 | "subStages": [
47 | {
48 | "stageId": "1",
49 | "state": "SCHEDULED",
50 | "done": false,
51 | "nodes": 1,
52 | "totalSplits": 0,
53 | "queuedSplits": 0,
54 | "runningSplits": 0,
55 | "completedSplits": 0,
56 | "userTimeMillis": 0,
57 | "cpuTimeMillis": 0,
58 | "wallTimeMillis": 0,
59 | "processedRows": 0,
60 | "processedBytes": 0,
61 | "subStages": []
62 | }
63 | ]
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------