You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by is...@apache.org on 2018/10/09 14:42:53 UTC
[4/9] ignite git commit: IGNITE-7783: PHP thin client
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Binary/TypeInfo.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Binary/TypeInfo.php b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/TypeInfo.php
new file mode 100644
index 0000000..9ab4057
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Binary/TypeInfo.php
@@ -0,0 +1,312 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Binary;
+
+use Apache\Ignite\Type\ObjectType;
+
+class TypeInfo
+{
+ const NAME = 'name';
+ const SIZE = 'size';
+ const MIN_VALUE = 'min';
+ const MAX_VALUE = 'max';
+ const MAX_UNSIGNED_VALUE = 'max_unsigned';
+ const NULLABLE = 'nullable';
+ const ELEMENT_TYPE_CODE = 'element_type';
+ const KEEP_ELEMENT_TYPE = 'keep_element_type';
+ const MAX_INT_VALUE = 2147483647;
+
+ private $properties;
+
+ private static $info;
+ private static $primitiveTypes;
+
+ public static function init(): void
+ {
+ TypeInfo::$info = array(
+ ObjectType::BYTE => new TypeInfo([
+ TypeInfo::NAME => 'byte',
+ TypeInfo::SIZE => 1,
+ TypeInfo::MIN_VALUE => -128,
+ TypeInfo::MAX_VALUE => 127,
+ TypeInfo::MAX_UNSIGNED_VALUE => 0x100,
+ ]),
+ ObjectType::SHORT => new TypeInfo([
+ TypeInfo::NAME => 'short',
+ TypeInfo::SIZE => 2,
+ TypeInfo::MIN_VALUE => -32768,
+ TypeInfo::MAX_VALUE => 32767,
+ TypeInfo::MAX_UNSIGNED_VALUE => 0x10000,
+ ]),
+ ObjectType::INTEGER => new TypeInfo([
+ TypeInfo::NAME => 'integer',
+ TypeInfo::SIZE => 4,
+ TypeInfo::MIN_VALUE => -2147483648,
+ TypeInfo::MAX_VALUE => TypeInfo::MAX_INT_VALUE,
+ ]),
+ ObjectType::LONG => new TypeInfo([
+ TypeInfo::NAME => 'long',
+ TypeInfo::SIZE => 8,
+ ]),
+ ObjectType::FLOAT => new TypeInfo([
+ TypeInfo::NAME => 'float',
+ TypeInfo::SIZE => 4,
+ ]),
+ ObjectType::DOUBLE => new TypeInfo([
+ TypeInfo::NAME => 'double',
+ TypeInfo::SIZE => 8,
+ ]),
+ ObjectType::CHAR => new TypeInfo([
+ TypeInfo::NAME => 'char',
+ TypeInfo::SIZE => 2,
+ ]),
+ ObjectType::BOOLEAN => new TypeInfo([
+ TypeInfo::NAME => 'boolean',
+ TypeInfo::SIZE => 1,
+ ]),
+ ObjectType::STRING => new TypeInfo([
+ TypeInfo::NAME => 'string',
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::UUID => new TypeInfo([
+ TypeInfo::NAME => 'UUID',
+ TypeInfo::SIZE => 16,
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::DATE => new TypeInfo([
+ TypeInfo::NAME => 'date',
+ TypeInfo::SIZE => 8,
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::BYTE_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'byte array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::BYTE
+ ]),
+ ObjectType::SHORT_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'short array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::SHORT
+ ]),
+ ObjectType::INTEGER_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'integer array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::INTEGER
+ ]),
+ ObjectType::LONG_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'long array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::LONG
+ ]),
+ ObjectType::FLOAT_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'float array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::FLOAT
+ ]),
+ ObjectType::DOUBLE_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'double array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::DOUBLE
+ ]),
+ ObjectType::CHAR_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'char array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::CHAR
+ ]),
+ ObjectType::BOOLEAN_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'boolean array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::BOOLEAN
+ ]),
+ ObjectType::STRING_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'string array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::STRING,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::UUID_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'UUID array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::UUID,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::DATE_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'date array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::DATE,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::OBJECT_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'object array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::COMPLEX_OBJECT,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::COLLECTION => new TypeInfo([
+ TypeInfo::NAME => 'collection',
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::MAP => new TypeInfo([
+ TypeInfo::NAME => 'map',
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::ENUM => new TypeInfo([
+ TypeInfo::NAME => 'enum',
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::ENUM_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'enum array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::ENUM,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::DECIMAL => new TypeInfo([
+ TypeInfo::NAME => 'decimal',
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::DECIMAL_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'decimal array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::DECIMAL,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::TIMESTAMP => new TypeInfo([
+ TypeInfo::NAME => 'timestamp',
+ TypeInfo::SIZE => 12,
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::TIMESTAMP_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'timestamp array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::TIMESTAMP,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::TIME => new TypeInfo([
+ TypeInfo::NAME => 'time',
+ TypeInfo::SIZE => 8,
+ TypeInfo::NULLABLE => true,
+ ]),
+ ObjectType::TIME_ARRAY => new TypeInfo([
+ TypeInfo::NAME => 'time array',
+ TypeInfo::NULLABLE => true,
+ TypeInfo::ELEMENT_TYPE_CODE => ObjectType::TIME,
+ TypeInfo::KEEP_ELEMENT_TYPE => true
+ ]),
+ ObjectType::NULL => new TypeInfo([
+ TypeInfo::NAME => 'null',
+ TypeInfo::NULLABLE => true,
+ ])
+ );
+
+ TypeInfo::$primitiveTypes = [
+ ObjectType::BYTE,
+ ObjectType::SHORT,
+ ObjectType::INTEGER,
+ ObjectType::LONG,
+ ObjectType::FLOAT,
+ ObjectType::DOUBLE,
+ ObjectType::CHAR,
+ ObjectType::BOOLEAN,
+ ObjectType::STRING,
+ ObjectType::UUID,
+ ObjectType::DATE,
+ ObjectType::BYTE_ARRAY,
+ ObjectType::SHORT_ARRAY,
+ ObjectType::INTEGER_ARRAY,
+ ObjectType::LONG_ARRAY,
+ ObjectType::FLOAT_ARRAY,
+ ObjectType::DOUBLE_ARRAY,
+ ObjectType::CHAR_ARRAY,
+ ObjectType::BOOLEAN_ARRAY,
+ ObjectType::STRING_ARRAY,
+ ObjectType::UUID_ARRAY,
+ ObjectType::DATE_ARRAY,
+ ObjectType::ENUM,
+ ObjectType::ENUM_ARRAY,
+ ObjectType::DECIMAL,
+ ObjectType::DECIMAL_ARRAY,
+ ObjectType::TIMESTAMP,
+ ObjectType::TIMESTAMP_ARRAY,
+ ObjectType::TIME,
+ ObjectType::TIME_ARRAY
+ ];
+ }
+
+ public static function getTypeInfo(int $typeCode): ?TypeInfo
+ {
+ return array_key_exists($typeCode, TypeInfo::$info) ? TypeInfo::$info[$typeCode] : null;
+ }
+
+ public static function getPrimitiveTypes(): array
+ {
+ return TypeInfo::$primitiveTypes;
+ }
+
+ private function __construct(array $properties)
+ {
+ $this->properties = $properties;
+ }
+
+ public function getName(): string
+ {
+ return $this->getProperty(TypeInfo::NAME, null);
+ }
+
+ public function getSize(): int
+ {
+ return $this->getProperty(TypeInfo::SIZE, 0);
+ }
+
+ public function isNullable(): bool
+ {
+ return $this->getProperty(TypeInfo::NULLABLE, false);
+ }
+
+ public function getElementTypeCode(): int
+ {
+ return $this->getProperty(TypeInfo::ELEMENT_TYPE_CODE, 0);
+ }
+
+ public function keepElementType(): bool
+ {
+ return $this->getProperty(TypeInfo::KEEP_ELEMENT_TYPE, false);
+ }
+
+ public function getMinValue()
+ {
+ return $this->getProperty(TypeInfo::MIN_VALUE, null);
+ }
+
+ public function getMaxValue()
+ {
+ return $this->getProperty(TypeInfo::MAX_VALUE, null);
+ }
+
+ public function getMaxUnsignedValue()
+ {
+ return $this->getProperty(TypeInfo::MAX_UNSIGNED_VALUE, null);
+ }
+
+ private function getProperty(string $propName, $defaultValue)
+ {
+ return array_key_exists($propName, $this->properties) ? $this->properties[$propName] : $defaultValue;
+ }
+}
+
+TypeInfo::init();
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Cache.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Cache.php b/modules/platforms/php/src/Apache/Ignite/Internal/Cache.php
new file mode 100644
index 0000000..fe0965e
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Cache.php
@@ -0,0 +1,387 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal;
+
+use Apache\Ignite\Cache\CacheInterface;
+use Apache\Ignite\Cache\CacheEntry;
+use Apache\Ignite\Query\Query;
+use Apache\Ignite\Query\CursorInterface;
+use Apache\Ignite\Internal\Binary\ClientOperation;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+
+class Cache implements CacheInterface
+{
+ private $name;
+ private $id;
+ private $keyType;
+ private $valueType;
+ private $communicator;
+
+ public function __construct(string $name, BinaryCommunicator $communicator)
+ {
+ $this->name = $name;
+ $this->id = Cache::calculateId($this->name);
+ $this->communicator = $communicator;
+ $this->keyType = null;
+ $this->valueType = null;
+ }
+
+ public static function calculateId(string $name)
+ {
+ return BinaryUtils::hashCode($name);
+ }
+
+ public function setKeyType($type): CacheInterface
+ {
+ BinaryUtils::checkObjectType($type, 'type');
+ $this->keyType = $type;
+ return $this;
+ }
+
+ public function setValueType($type): CacheInterface
+ {
+ BinaryUtils::checkObjectType($type, 'type');
+ $this->valueType = $type;
+ return $this;
+ }
+
+ public function get($key)
+ {
+ return $this->writeKeyReadValueOp(ClientOperation::CACHE_GET, $key);
+ }
+
+ public function getAll(array $keys): array
+ {
+ ArgumentChecker::notEmpty($keys, 'keys');
+ $result = [];
+ $this->communicator->send(
+ ClientOperation::CACHE_GET_ALL,
+ function (MessageBuffer $payload) use ($keys)
+ {
+ $this->writeCacheInfo($payload);
+ $this->writeKeys($payload, $keys);
+ },
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $resultCount = $payload->readInteger();
+ for ($i = 0; $i < $resultCount; $i++) {
+ array_push($result, new CacheEntry(
+ $this->communicator->readObject($payload, $this->keyType),
+ $this->communicator->readObject($payload, $this->valueType)));
+ }
+ });
+ return $result;
+ }
+
+ public function put($key, $value): void
+ {
+ $this->writeKeyValueOp(ClientOperation::CACHE_PUT, $key, $value);
+ }
+
+ public function putAll(array $entries): void
+ {
+ ArgumentChecker::notEmpty($entries, 'entries');
+ ArgumentChecker::hasType($entries, 'entries', true, CacheEntry::class);
+ $this->communicator->send(
+ ClientOperation::CACHE_PUT_ALL,
+ function (MessageBuffer $payload) use ($entries)
+ {
+ $this->writeCacheInfo($payload);
+ $payload->writeInteger(count($entries));
+ foreach ($entries as $entry) {
+ $this->writeKeyValue($payload, $entry->getKey(), $entry->getValue());
+ }
+ });
+ }
+
+ public function containsKey($key): bool
+ {
+ return $this->writeKeyReadBooleanOp(ClientOperation::CACHE_CONTAINS_KEY, $key);
+ }
+
+ public function containsKeys(array $keys): bool
+ {
+ return $this->writeKeysReadBooleanOp(ClientOperation::CACHE_CONTAINS_KEYS, $keys);
+ }
+
+ public function getAndPut($key, $value)
+ {
+ return $this->writeKeyValueReadValueOp(ClientOperation::CACHE_GET_AND_PUT, $key, $value);
+ }
+
+ public function getAndReplace($key, $value)
+ {
+ return $this->writeKeyValueReadValueOp(ClientOperation::CACHE_GET_AND_REPLACE, $key, $value);
+ }
+
+ public function getAndRemove($key)
+ {
+ return $this->writeKeyReadValueOp(ClientOperation::CACHE_GET_AND_REMOVE, $key);
+ }
+
+ public function putIfAbsent($key, $value): bool
+ {
+ return $this->writeKeyValueReadBooleanOp(ClientOperation::CACHE_PUT_IF_ABSENT, $key, $value);
+ }
+
+ public function getAndPutIfAbsent($key, $value)
+ {
+ return $this->writeKeyValueReadValueOp(ClientOperation::CACHE_GET_AND_PUT_IF_ABSENT, $key, $value);
+ }
+
+ public function replace($key, $value): bool
+ {
+ return $this->writeKeyValueReadBooleanOp(ClientOperation::CACHE_REPLACE, $key, $value);
+ }
+
+ public function replaceIfEquals($key, $value, $newValue): bool
+ {
+ ArgumentChecker::notNull($key, 'key');
+ ArgumentChecker::notNull($value, 'value');
+ ArgumentChecker::notNull($newValue, 'newValue');
+ $result = false;
+ $this->communicator->send(
+ ClientOperation::CACHE_REPLACE_IF_EQUALS,
+ function (MessageBuffer $payload) use ($key, $value, $newValue)
+ {
+ $this->writeCacheInfo($payload);
+ $this->writeKeyValue($payload, $key, $value);
+ $this->communicator->writeObject($payload, $newValue, $this->valueType);
+ },
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $result = $payload->readBoolean();
+ });
+ return $result;
+ }
+
+ public function clear(): void
+ {
+ $this->communicator->send(
+ ClientOperation::CACHE_CLEAR,
+ function (MessageBuffer $payload)
+ {
+ $this->writeCacheInfo($payload);
+ });
+ }
+
+ public function clearKey($key): void
+ {
+ $this->writeKeyOp(ClientOperation::CACHE_CLEAR_KEY, $key);
+ }
+
+ public function clearKeys($keys): void
+ {
+ $this->writeKeysOp(ClientOperation::CACHE_CLEAR_KEYS, $keys);
+ }
+
+ public function removeKey($key): bool
+ {
+ return $this->writeKeyReadBooleanOp(ClientOperation::CACHE_REMOVE_KEY, $key);
+ }
+
+ public function removeIfEquals($key, $value): bool
+ {
+ return $this->writeKeyValueReadBooleanOp(ClientOperation::CACHE_REMOVE_IF_EQUALS, $key, $value);
+ }
+
+ public function removeKeys($keys): void
+ {
+ $this->writeKeysOp(ClientOperation::CACHE_REMOVE_KEYS, $keys);
+ }
+
+ public function removeAll(): void
+ {
+ $this->communicator->send(
+ ClientOperation::CACHE_REMOVE_ALL,
+ function (MessageBuffer $payload)
+ {
+ $this->writeCacheInfo($payload);
+ });
+ }
+
+ public function getSize(int ...$peekModes): int
+ {
+ ArgumentChecker::hasValueFrom($peekModes, 'peekModes', true, [
+ CacheInterface::PEEK_MODE_ALL,
+ CacheInterface::PEEK_MODE_NEAR,
+ CacheInterface::PEEK_MODE_PRIMARY,
+ CacheInterface::PEEK_MODE_BACKUP
+ ]);
+ $result = 0;
+ $this->communicator->send(
+ ClientOperation::CACHE_GET_SIZE,
+ function (MessageBuffer $payload) use ($peekModes)
+ {
+ $this->writeCacheInfo($payload);
+ $payload->writeInteger(count($peekModes));
+ foreach ($peekModes as $mode) {
+ $payload->writeByte($mode);
+ }
+ },
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $result = $payload->readLong();
+ });
+ return $result;
+ }
+
+ public function query(Query $query): CursorInterface
+ {
+ $value = null;
+ $this->communicator->send(
+ $query->getOperation(),
+ function (MessageBuffer $payload) use ($query)
+ {
+ $this->writeCacheInfo($payload);
+ $query->write($this->communicator, $payload);
+ },
+ function (MessageBuffer $payload) use ($query, &$value)
+ {
+ $value = $query->getCursor($this->communicator, $payload, $this->keyType, $this->valueType);
+ });
+ return $value;
+ }
+
+ private function writeCacheInfo(MessageBuffer $payload): void
+ {
+ $payload->writeInteger($this->id);
+ $payload->writeByte(0);
+ }
+
+ private function writeKeyValueOp(int $operation, $key, $value, callable $payloadReader = null): void
+ {
+ ArgumentChecker::notNull($key, 'key');
+ ArgumentChecker::notNull($value, 'value');
+ $this->communicator->send(
+ $operation,
+ function (MessageBuffer $payload) use ($key, $value)
+ {
+ $this->writeCacheInfo($payload);
+ $this->writeKeyValue($payload, $key, $value);
+ },
+ $payloadReader);
+ }
+
+ private function writeKeyValueReadValueOp(int $operation, $key, $value)
+ {
+ $result = null;
+ $this->writeKeyValueOp(
+ $operation, $key, $value,
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $result = $this->communicator->readObject($payload, $this->valueType);
+ });
+ return $result;
+ }
+
+ private function writeKeyValueReadBooleanOp(int $operation, $key, $value): bool
+ {
+ $result = false;
+ $this->writeKeyValueOp(
+ $operation, $key, $value,
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $result = $payload->readBoolean();
+ });
+ return $result;
+ }
+
+ private function writeKeyReadValueOp(int $operation, $key)
+ {
+ $value = null;
+ $this->writeKeyOp(
+ $operation, $key,
+ function (MessageBuffer $payload) use (&$value)
+ {
+ $value = $this->communicator->readObject($payload, $this->valueType);
+ });
+ return $value;
+ }
+
+ private function writeKeyOp(int $operation, $key, callable $payloadReader = null): void
+ {
+ ArgumentChecker::notNull($key, 'key');
+ $this->communicator->send(
+ $operation,
+ function (MessageBuffer $payload) use ($key)
+ {
+ $this->writeCacheInfo($payload);
+ $this->communicator->writeObject($payload, $key, $this->keyType);
+ },
+ $payloadReader);
+ }
+
+ private function writeKeyReadBooleanOp(int $operation, $key): bool
+ {
+ $result = false;
+ $this->writeKeyOp(
+ $operation,
+ $key,
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $result = $payload->readBoolean();
+ });
+ return $result;
+
+ }
+
+ private function writeKeys(MessageBuffer $payload, array $keys): void
+ {
+ $payload->writeInteger(count($keys));
+ foreach ($keys as $key) {
+ $this->communicator->writeObject($payload, $key, $this->keyType);
+ }
+ }
+
+ private function writeKeysReadBooleanOp(int $operation, array $keys): bool
+ {
+ $result = false;
+ $this->writeKeysOp(
+ $operation,
+ $keys,
+ function (MessageBuffer $payload) use (&$result)
+ {
+ $result = $payload->readBoolean();
+ });
+ return $result;
+ }
+
+ private function writeKeysOp(int $operation, array $keys, callable $payloadReader = null): void
+ {
+ ArgumentChecker::notEmpty($keys, 'keys');
+ $this->communicator->send(
+ $operation,
+ function (MessageBuffer $payload) use ($keys)
+ {
+ $this->writeCacheInfo($payload);
+ $this->writeKeys($payload, $keys);
+ },
+ $payloadReader);
+ }
+
+ private function writeKeyValue(MessageBuffer $payload, $key, $value): void
+ {
+ $this->communicator->writeObject($payload, $key, $this->keyType);
+ $this->communicator->writeObject($payload, $value, $this->valueType);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientFailoverSocket.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientFailoverSocket.php b/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientFailoverSocket.php
new file mode 100644
index 0000000..2600698
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientFailoverSocket.php
@@ -0,0 +1,134 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Connection;
+
+use Apache\Ignite\ClientConfiguration;
+use Apache\Ignite\Exception\NoConnectionException;
+use Apache\Ignite\Exception\OperationStatusUnknownException;
+use Apache\Ignite\Internal\Utils\Logger;
+
+class ClientFailoverSocket
+{
+ const STATE_DISCONNECTED = 0;
+ const STATE_CONNECTING = 1;
+ const STATE_CONNECTED = 2;
+
+ private $socket;
+ private $state;
+ private $config;
+ private $endpointsNumber;
+ private $endpointIndex;
+ private $reconnectRequired;
+
+ public function __construct()
+ {
+ $this->socket = null;
+ $this->state = ClientFailoverSocket::STATE_DISCONNECTED;
+ $this->reconnectRequired = false;
+ }
+
+ public function connect(ClientConfiguration $config): void
+ {
+ if ($this->state !== ClientFailoverSocket::STATE_DISCONNECTED) {
+ $this->disconnect();
+ }
+ $this->config = $config;
+ $this->endpointsNumber = count($this->config->getEndpoints());
+ $this->endpointIndex = rand(0, $this->endpointsNumber - 1);
+ $this->failoverConnect();
+ }
+
+ public function send(int $opCode, ?callable $payloadWriter, callable $payloadReader = null): void
+ {
+ if ($this->reconnectRequired) {
+ $this->failoverConnect();
+ $this->reconnectRequired = false;
+ }
+ if ($this->state !== ClientFailoverSocket::STATE_CONNECTED) {
+ throw new NoConnectionException();
+ }
+ try {
+ $this->socket->sendRequest($opCode, $payloadWriter, $payloadReader);
+ } catch (OperationStatusUnknownException $e) {
+ $this->disconnect();
+ $this->endpointIndex++;
+ $this->reconnectRequired = true;
+ throw $e;
+ }
+ }
+
+ public function disconnect(): void
+ {
+ if ($this->state !== ClientFailoverSocket::STATE_DISCONNECTED) {
+ $this->changeState(ClientFailoverSocket::STATE_DISCONNECTED);
+ if ($this->socket) {
+ $this->socket->disconnect();
+ $this->socket = null;
+ }
+ }
+ }
+
+ private function failoverConnect(): void
+ {
+ $errors = [];
+ for ($i = 0; $i < $this->endpointsNumber; $i++) {
+ $index = ($this->endpointIndex + $i) % $this->endpointsNumber;
+ $endpoint = $this->config->getEndpoints()[$index];
+ try {
+ $this->changeState(ClientFailoverSocket::STATE_CONNECTING, $endpoint);
+ $this->socket = new ClientSocket($endpoint, $this->config);
+ $this->socket->connect();
+ $this->changeState(ClientFailoverSocket::STATE_CONNECTED, $endpoint);
+ $this->endpointIndex = $index;
+ return;
+ } catch (NoConnectionException $e) {
+ Logger::logError($e->getMessage());
+ array_push($errors, sprintf('[%s] %s', $endpoint, $e->getMessage()));
+ $this->changeState(ClientFailoverSocket::STATE_DISCONNECTED, $endpoint);
+ }
+ }
+ $this->socket = null;
+ throw new NoConnectionException(implode(';', $errors));
+ }
+
+ private function changeState(int $state, ?string $endpoint = null): void
+ {
+ if (Logger::isDebug()) {
+ Logger::logDebug(sprintf('Socket %s: %s -> %s',
+ $endpoint ? $endpoint : ($this->socket ? $this->socket->getEndpoint() : ''),
+ $this->getState($this->state),
+ $this->getState($state)));
+ }
+ $this->state = $state;
+ }
+
+ private function getState(int $state)
+ {
+ switch ($state) {
+ case ClientFailoverSocket::STATE_DISCONNECTED:
+ return 'DISCONNECTED';
+ case ClientFailoverSocket::STATE_CONNECTING:
+ return 'CONNECTING';
+ case ClientFailoverSocket::STATE_CONNECTED:
+ return 'CONNECTED';
+ default:
+ return 'UNKNOWN';
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientSocket.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientSocket.php b/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientSocket.php
new file mode 100644
index 0000000..a35bb15
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ClientSocket.php
@@ -0,0 +1,247 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Connection;
+
+use Apache\Ignite\ClientConfiguration;
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Internal\Utils\Logger;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\Request;
+use Apache\Ignite\Exception\NoConnectionException;
+use Apache\Ignite\Exception\OperationException;
+use Apache\Ignite\Exception\OperationStatusUnknownException;
+
+class ClientSocket
+{
+ const HANDSHAKE_SUCCESS_STATUS_CODE = 1;
+ const REQUEST_SUCCESS_STATUS_CODE = 0;
+ const PORT_DEFAULT = 10800;
+ const SOCKET_CHUNK_SIZE_DEFAULT = 8192;
+ const HANDSHAKE_CODE = 1;
+ const CLIENT_CODE = 2;
+
+ private static $currentVersion;
+ private static $supportedVersions;
+
+ private $endpoint;
+ private $config;
+ private $socket;
+ private $sendChunkSize;
+ private $receiveChunkSize;
+ private $protocolVersion;
+
+ public function __construct(string $endpoint, ClientConfiguration $config)
+ {
+ $this->endpoint = $endpoint;
+ $this->config = $config;
+ $this->socket = null;
+ $this->sendChunkSize = $config->getSendChunkSize() > 0 ?
+ $config->getSendChunkSize() :
+ self::SOCKET_CHUNK_SIZE_DEFAULT;
+ $this->receiveChunkSize = $config->getReceiveChunkSize() > 0 ?
+ $config->getReceiveChunkSize() :
+ self::SOCKET_CHUNK_SIZE_DEFAULT;
+ $this->protocolVersion = null;
+ }
+
+ public function __destruct()
+ {
+ $this->disconnect();
+ }
+
+ public static function init(): void
+ {
+ ClientSocket::$currentVersion = ProtocolVersion::$V_1_2_0;
+ ClientSocket::$supportedVersions = [
+ ProtocolVersion::$V_1_2_0
+ ];
+ }
+
+ public function getEndpoint(): string
+ {
+ return $this->endpoint;
+ }
+
+ public function connect(): void
+ {
+ $tlsOptions = $this->config->getTLSOptions();
+ $options = ['socket' => ['tcp_nodelay' => $this->config->getTcpNoDelay()]];
+ if ($tlsOptions) {
+ $options['ssl'] = $tlsOptions;
+ }
+ $context = stream_context_create($options);
+ $errno = 0;
+ $errstr = null;
+ if (!($this->socket = stream_socket_client(
+ ($tlsOptions ? 'ssl://' : 'tcp://') . $this->endpoint,
+ $errno,
+ $errstr,
+ ini_get('default_socket_timeout'),
+ STREAM_CLIENT_CONNECT,
+ $context))) {
+ throw new NoConnectionException($errstr);
+ }
+ if ($this->config->getTimeout() > 0) {
+ $timeout = $this->config->getTimeout();
+ stream_set_timeout($this->socket, intdiv($timeout, 1000), $timeout % 1000);
+ }
+ // send handshake
+ $this->processRequest($this->getHandshakeRequest(ClientSocket::$currentVersion));
+ }
+
+ public function disconnect(): void
+ {
+ if ($this->socket !== false && $this->socket !== null) {
+ fclose($this->socket);
+ $this->socket = null;
+ }
+ }
+
+ private function getHandshakeRequest($version): Request
+ {
+ $this->protocolVersion = $version;
+ return new Request(-1, array($this, 'handshakePayloadWriter'), null, true);
+ }
+
+ public function handshakePayloadWriter(MessageBuffer $buffer): void
+ {
+ // Handshake code
+ $buffer->writeByte(ClientSocket::HANDSHAKE_CODE);
+ // Protocol version
+ $this->protocolVersion->write($buffer);
+ // Client code
+ $buffer->writeByte(ClientSocket::CLIENT_CODE);
+ if ($this->config->getUserName()) {
+ BinaryCommunicator::writeString($buffer, $this->config->getUserName());
+ BinaryCommunicator::writeString($buffer, $this->config->getPassword());
+ }
+ }
+
+ public function sendRequest(int $opCode, ?callable $payloadWriter, callable $payloadReader = null): void
+ {
+ $request = new Request($opCode, $payloadWriter, $payloadReader);
+ $this->processRequest($request);
+ }
+
+ private function processRequest(Request $request): void
+ {
+ $buffer = $request->getMessage();
+ $this->logMessage($request->getId(), true, $buffer);
+ $data = $buffer->getBuffer();
+ while (($length = strlen($data)) > 0) {
+ $written = fwrite($this->socket, $data, $this->sendChunkSize);
+ if ($length === $written) {
+ break;
+ }
+ if ($written === false || $written === 0) {
+ throw new OperationStatusUnknownException('Error while writing data to the server');
+ }
+ $data = substr($data, $written);
+ }
+ $this->processResponse($request);
+ }
+
+ private function receive(MessageBuffer $buffer, int $minSize): void
+ {
+ while ($buffer->getLength() < $minSize)
+ {
+ $chunk = fread($this->socket, $this->receiveChunkSize);
+ if ($chunk === false || $chunk === '') {
+ throw new OperationStatusUnknownException('Error while reading data from the server');
+ } else {
+ $buffer->append($chunk);
+ }
+ }
+ }
+
+ private function processResponse(Request $request): void
+ {
+ $buffer = new MessageBuffer(0);
+ $this->receive($buffer, BinaryUtils::getSize(ObjectType::INTEGER));
+ // Response length
+ $length = $buffer->readInteger();
+ $this->receive($buffer, $length + BinaryUtils::getSize(ObjectType::INTEGER));
+ if ($request->isHandshake()) {
+ $this->processHandshake($buffer);
+ } else {
+ // Request id
+ $requestId = $buffer->readLong();
+ if (!BinaryUtils::floatEquals($requestId, $request->getId())) {
+ BinaryUtils::internalError('Invalid response id: ' . $requestId);
+ }
+ // Status code
+ $isSuccess = ($buffer->readInteger() === ClientSocket::REQUEST_SUCCESS_STATUS_CODE);
+ if (!$isSuccess) {
+ // Error message
+ $errMessage = BinaryCommunicator::readString($buffer);
+ throw new OperationException($errMessage);
+ } else {
+ $payloadReader = $request->getPayloadReader();
+ if ($payloadReader) {
+ call_user_func($payloadReader, $buffer);
+ }
+ }
+ }
+ $this->logMessage($request->getId(), false, $buffer);
+ }
+
+ private function processHandshake(MessageBuffer $buffer): void
+ {
+ // Handshake status
+ if ($buffer->readByte() === ClientSocket::HANDSHAKE_SUCCESS_STATUS_CODE) {
+ return;
+ }
+ // Server protocol version
+ $serverVersion = new ProtocolVersion();
+ $serverVersion->read($buffer);
+ // Error message
+ $errMessage = BinaryCommunicator::readString($buffer);
+
+ if (!$this->isSupportedVersion($serverVersion)) {
+ throw new OperationException(
+ sprintf('Protocol version mismatch: client %s / server %s. Server details: %s',
+ $this->protocolVersion->toString(), $serverVersion->toString(), $errMessage));
+ } else {
+ $this->disconnect();
+ throw new OperationException($errMessage);
+ }
+ }
+
+ private function isSupportedVersion(ProtocolVersion $version): bool
+ {
+ foreach (ClientSocket::$supportedVersions as $supportedVersion) {
+ if ($supportedVersion->equals($version)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private function logMessage(int $requestId, bool $isRequest, MessageBuffer $buffer): void
+ {
+ if (Logger::isDebug()) {
+ Logger::logDebug(($isRequest ? 'Request: ' : 'Response: ') . $requestId);
+ Logger::logBuffer($buffer);
+ }
+ }
+}
+
+ClientSocket::init();
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ProtocolVersion.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ProtocolVersion.php b/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ProtocolVersion.php
new file mode 100644
index 0000000..3c3a64b
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Connection/ProtocolVersion.php
@@ -0,0 +1,82 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Connection;
+
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+
+class ProtocolVersion
+{
+ public static $V_1_2_0;
+
+ private $major;
+ private $minor;
+ private $patch;
+
+ public static function init(): void
+ {
+ ProtocolVersion::$V_1_2_0 = new ProtocolVersion(1, 2, 0);
+ }
+
+ public function __construct(int $major = 0, int $minor = 0, int $patch = 0)
+ {
+ $this->major = $major;
+ $this->minor = $minor;
+ $this->patch = $patch;
+ }
+
+ public function compareTo(ProtocolVersion $other): int
+ {
+ $diff = $this->major - $other->major;
+ if ($diff !== 0) {
+ return $diff;
+ }
+ $diff = $this->minor - $other->minor;
+ if ($diff !== 0) {
+ return $diff;
+ }
+ return $this->patch - $other->patch;
+ }
+
+ public function equals(ProtocolVersion $other): bool
+ {
+ return $this->compareTo($other) === 0;
+ }
+
+ public function toString(): string
+ {
+ return sprintf('%d.%d.%d', $this->major, $this->minor, $this->patch);
+ }
+
+ public function read(MessageBuffer $buffer): void
+ {
+ $this->major = $buffer->readShort();
+ $this->minor = $buffer->readShort();
+ $this->patch = $buffer->readShort();
+ }
+
+ public function write(MessageBuffer $buffer): void
+ {
+ $buffer->writeShort($this->major);
+ $buffer->writeShort($this->minor);
+ $buffer->writeShort($this->patch);
+ }
+}
+
+ProtocolVersion::init();
+
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Query/Cursor.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Query/Cursor.php b/modules/platforms/php/src/Apache/Ignite/Internal/Query/Cursor.php
new file mode 100644
index 0000000..a228dd4
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Query/Cursor.php
@@ -0,0 +1,166 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Query;
+
+use Apache\Ignite\Cache\CacheEntry;
+use Apache\Ignite\Query\CursorInterface;
+use Apache\Ignite\Internal\Binary\ClientOperation;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+
+class Cursor implements CursorInterface
+{
+ protected $communicator;
+ private $operation;
+ private $buffer;
+ private $keyType;
+ private $valueType;
+ protected $id;
+ private $hasNext;
+ private $values;
+ private $valueIndex;
+ private $rewinds;
+ private $index;
+
+ public function __construct(BinaryCommunicator $communicator, int $operation, MessageBuffer $buffer, $keyType = null, $valueType = null)
+ {
+ $this->communicator = $communicator;
+ $this->operation = $operation;
+ $this->buffer = $buffer;
+ $this->keyType = $keyType;
+ $this->valueType = $valueType;
+ $this->id = null;
+ $this->hasNext = false;
+ $this->values = null;
+ $this->valueIndex = 0;
+ $this->rewinds = 0;
+ $this->index = 0;
+ }
+
+ public function current()
+ {
+ return $this->values[$this->valueIndex];
+ }
+
+ public function key()
+ {
+ return $this->index;
+ }
+
+ public function next()
+ {
+ $this->valueIndex++;
+ $this->index++;
+ }
+
+ public function rewind(): void
+ {
+ $this->rewinds++;
+ }
+
+ public function valid(): bool
+ {
+ if ($this->rewinds > 1) {
+ return false;
+ }
+ if (!$this->values || $this->valueIndex >= count($this->values)) {
+ $this->obtainValues();
+ $this->valueIndex = 0;
+ }
+ return $this->values && $this->valueIndex < count($this->values);
+ }
+
+ public function getAll(): array
+ {
+ $result = [];
+ foreach ($this as $value) {
+ array_push($result, $value);
+ }
+ return $result;
+ }
+
+ public function close(): void
+ {
+ // Close cursor only if the server has more pages: the server closes cursor automatically on last page
+ if ($this->id && $this->hasNext) {
+ $this->communicator->send(
+ ClientOperation::RESOURCE_CLOSE,
+ function (MessageBuffer $payload)
+ {
+ $this->write($payload);
+ });
+ }
+ }
+
+ private function getNext(): void
+ {
+ $this->hasNext = false;
+ $this->values = null;
+ $this->buffer = null;
+ $this->communicator->send(
+ $this->operation,
+ function (MessageBuffer $payload)
+ {
+ $this->write($payload);
+ },
+ function (MessageBuffer $payload)
+ {
+ $this->buffer = $payload;
+ });
+ }
+
+ private function obtainValues(): void
+ {
+ if (!$this->buffer && $this->hasNext) {
+ $this->getNext();
+ }
+ $this->values = null;
+ if ($this->buffer) {
+ $this->read($this->buffer);
+ $this->buffer = null;
+ }
+ }
+
+ private function write(MessageBuffer $buffer): void
+ {
+ $buffer->writeLong($this->id);
+ }
+
+ public function readId(MessageBuffer $buffer): void
+ {
+ $this->id = $buffer->readLong();
+ }
+
+ protected function readRow(MessageBuffer $buffer)
+ {
+ return new CacheEntry(
+ $this->communicator->readObject($buffer, $this->keyType),
+ $this->communicator->readObject($buffer, $this->valueType));
+ }
+
+ private function read(MessageBuffer $buffer): void
+ {
+ $rowCount = $buffer->readInteger();
+ $this->values = [];
+ for ($i = 0; $i < $rowCount; $i++) {
+ array_push($this->values, $this->readRow($buffer));
+ }
+ $this->hasNext = $buffer->readBoolean();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Query/SqlFieldsCursor.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Query/SqlFieldsCursor.php b/modules/platforms/php/src/Apache/Ignite/Internal/Query/SqlFieldsCursor.php
new file mode 100644
index 0000000..e876baf
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Query/SqlFieldsCursor.php
@@ -0,0 +1,75 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Query;
+
+use Apache\Ignite\Query\SqlFieldsCursorInterface;
+use Apache\Ignite\Internal\Binary\ClientOperation;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+
+class SqlFieldsCursor extends Cursor implements SqlFieldsCursorInterface
+{
+ private $fieldCount;
+ private $fieldNames;
+ private $fieldTypes;
+
+ public function __construct(BinaryCommunicator $communicator, MessageBuffer $buffer)
+ {
+ parent::__construct($communicator, ClientOperation::QUERY_SQL_FIELDS_CURSOR_GET_PAGE, $buffer);
+ $this->fieldCount = 0;
+ $this->fieldNames = [];
+ $this->fieldTypes = null;
+ }
+
+ public function getFieldNames(): array
+ {
+ return $this->fieldNames;
+ }
+
+ public function setFieldTypes(...$fieldTypes): SqlFieldsCursorInterface
+ {
+ foreach ($fieldTypes as $fieldType) {
+ BinaryUtils::checkObjectType($fieldType, 'fieldTypes');
+ }
+ $this->fieldTypes = $fieldTypes;
+ return $this;
+ }
+
+ public function readFieldNames(MessageBuffer $buffer, bool $includeFieldNames): void
+ {
+ $this->id = $buffer->readLong();
+ $this->fieldCount = $buffer->readInteger();
+ if ($includeFieldNames) {
+ for ($i = 0; $i < $this->fieldCount; $i++) {
+ array_push($this->fieldNames, $this->communicator->readObject($buffer));
+ }
+ }
+ }
+
+ protected function readRow(MessageBuffer $buffer)
+ {
+ $values = [];
+ for ($i = 0; $i < $this->fieldCount; $i++) {
+ $fieldType = $this->fieldTypes && $i < count($this->fieldTypes) ? $this->fieldTypes[$i] : null;
+ array_push($values, $this->communicator->readObject($buffer, $fieldType));
+ }
+ return $values;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Utils/ArgumentChecker.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Utils/ArgumentChecker.php b/modules/platforms/php/src/Apache/Ignite/Internal/Utils/ArgumentChecker.php
new file mode 100644
index 0000000..bd04f10
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Utils/ArgumentChecker.php
@@ -0,0 +1,87 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Utils;
+
+use Apache\Ignite\Exception\ClientException;
+
+class ArgumentChecker
+{
+ public static function notEmpty($arg, string $argName): void
+ {
+ if (empty($arg)) {
+ ArgumentChecker::illegalArgument(sprintf('"%s" argument should not be empty', $argName));
+ }
+ }
+
+ public static function notNull($arg, string $argName): void
+ {
+ if (is_null($arg)) {
+ ArgumentChecker::illegalArgument(sprintf('"%s" argument should not be null', $argName));
+ }
+ }
+
+ public static function hasType($arg, string $argName, bool $isArray, ...$types): void
+ {
+ if ($arg === null) {
+ return;
+ }
+ if ($isArray && is_array($arg)) {
+ foreach ($arg as $a) {
+ ArgumentChecker::hasType($a, $argName, false, ...$types);
+ }
+ } else {
+ foreach ($types as $type) {
+ if ($arg instanceof $type) {
+ return;
+ }
+ }
+ ArgumentChecker::illegalArgument(sprintf('"%s" argument has incorrect type', $argName));
+ }
+ }
+
+ public static function hasValueFrom($arg, string $argName, bool $isArray, array $values): void
+ {
+ if ($isArray && is_array($arg)) {
+ foreach ($arg as $a) {
+ ArgumentChecker::hasValueFrom($a, $argName, false, $values);
+ }
+ } else {
+ if (!in_array($arg, $values)) {
+ ArgumentChecker::invalidValue($argName);
+ }
+ }
+ }
+
+ public static function invalidValue(string $argName): void
+ {
+ ArgumentChecker::illegalArgument(sprintf('"%s" argument has incorrect value', $argName));
+ }
+
+ public static function invalidArgument($arg, string $argName, string $typeName): void
+ {
+ if ($arg !== null) {
+ ArgumentChecker::illegalArgument(sprintf('"%s" argument is invalid for %s', $argName, $typeName));
+ }
+ }
+
+ public static function illegalArgument($message): void
+ {
+ throw new ClientException($message);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Internal/Utils/Logger.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Internal/Utils/Logger.php b/modules/platforms/php/src/Apache/Ignite/Internal/Utils/Logger.php
new file mode 100644
index 0000000..1faf9ca
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Internal/Utils/Logger.php
@@ -0,0 +1,62 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Internal\Utils;
+
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+
+/** Utility class for logging errors and debug messages. */
+class Logger
+{
+ private static $debug = false;
+
+ public static function isDebug(): bool
+ {
+ return Logger::$debug;
+ }
+
+ public static function setDebug(bool $debug): void
+ {
+ Logger::$debug = $debug;
+ }
+
+ public static function logDebug($data, ...$args): void
+ {
+ if (Logger::$debug) {
+ echo(sprintf($data, ...$args) . PHP_EOL);
+ }
+ }
+
+ public static function logError($data, ...$args): void
+ {
+ if (Logger::$debug) {
+ echo(sprintf("ERROR: $data", ...$args) . PHP_EOL);
+ }
+ }
+
+ public static function logBuffer(MessageBuffer $buffer, int $startPos = 0, int $length = -1): void
+ {
+ if (Logger::$debug) {
+ if ($length < 0) {
+ $length = $buffer->getLength();
+ }
+ $message = $buffer->getSlice($startPos, $length);
+ Logger::logDebug('[' . implode(',', array_map('ord', str_split($message))) . ']');
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Query/CursorInterface.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Query/CursorInterface.php b/modules/platforms/php/src/Apache/Ignite/Query/CursorInterface.php
new file mode 100644
index 0000000..1525e28
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Query/CursorInterface.php
@@ -0,0 +1,56 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Query;
+
+/**
+ * Interface representing a cursor to obtain results of SQL and Scan query operations.
+ *
+ * An instance of the class with this interface should be obtained via query() method
+ * of an object with CacheInterface.
+ * One instance of the class with CursorInterface returns results of one SQL or Scan query operation.
+ *
+ * CursorInterface extends the PHP Iterator interface.
+ * The PHP Iterator's methods may be used to obtain the results of the query (cache entries, i.e. key-value pairs)
+ * one by one.
+ * Also, the cursor can be placed into the "foreach" PHP loop to easily iterate over all the results.
+ *
+ * Additionally, CursorInterface includes getAll() method to get all the results at once
+ * and close() method to prematurely close the cursor.
+ *
+ */
+interface CursorInterface extends \Iterator
+{
+ /**
+ * Returns all elements (cache entries, i.e. key-value pairs) from the query results at once.
+ *
+ * May be used instead of the PHP Iterator's methods if the number of returned entries
+ * is relatively small and will not cause memory utilization issues.
+ *
+ * @return array all cache entries (key-value pairs) returned by SQL or Scan query.
+ */
+ public function getAll(): array;
+
+ /**
+ * Closes the cursor. Obtaining elements from the results is not possible after this.
+ *
+ * This method should be called if no more elements are needed.
+ * It is not necessary to call it if all elements have been already obtained.
+ */
+ public function close(): void;
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Query/Query.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Query/Query.php b/modules/platforms/php/src/Apache/Ignite/Query/Query.php
new file mode 100644
index 0000000..2cd3aec
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Query/Query.php
@@ -0,0 +1,70 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Query;
+
+/**
+ * Base class representing an Ignite SQL or Scan query.
+ *
+ * The class is abstract, only subclasses may be instantiated.
+ */
+abstract class Query
+{
+ const PAGE_SIZE_DEFAULT = 1024;
+
+ protected $local;
+ protected $operation;
+ protected $pageSize;
+
+ protected function __construct(int $operation)
+ {
+ $this->operation = $operation;
+ $this->local = false;
+ $this->pageSize = Query::PAGE_SIZE_DEFAULT;
+ }
+
+ /**
+ * Set local query flag.
+ *
+ * @param bool $local local query flag: true or false.
+ * @return Query the same instance of the Query.
+ */
+ public function setLocal(bool $local): Query
+ {
+ $this->local = $local;
+ return $this;
+ }
+
+ /**
+ * Set cursor page size.
+ *
+ * @param int $pageSize cursor page size.
+ * @return Query the same instance of the Query.
+ */
+ public function setPageSize(int $pageSize): Query
+ {
+ $this->pageSize = $pageSize;
+ return $this;
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function getOperation(): int
+ {
+ return $this->operation;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Query/ScanQuery.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Query/ScanQuery.php b/modules/platforms/php/src/Apache/Ignite/Query/ScanQuery.php
new file mode 100644
index 0000000..85391b6
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Query/ScanQuery.php
@@ -0,0 +1,88 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Query;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\ClientOperation;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Query\Cursor;
+
+/**
+ * Class representing a Scan query which returns the whole cache entries (key-value pairs).
+ *
+ * This version of the class does not support a possibility to specify a Filter object for the query.
+ * The query returns all entries from the entire cache or from the specified partition.
+ */
+class ScanQuery extends Query
+{
+ private $partitionNumber;
+
+ /**
+ * Public constructor.
+ *
+ * Scan query settings have the following defaults:
+ * <pre>
+ * Scan Query setting : Default value
+ * Local query flag : false
+ * Cursor page size : 1024
+ * Partition number : -1 (entire cache)
+ * Filter object : null (not supported)
+ * </pre>
+ * Every setting (except Filter object) may be changed using set methods.
+ */
+ public function __construct()
+ {
+ parent::__construct(ClientOperation::QUERY_SCAN);
+ $this->partitionNumber = -1;
+ }
+
+ /**
+ * Sets a partition number over which this query should iterate.
+ *
+ * If negative, the query will iterate over all partitions in the cache.
+ *
+ * @param int $partitionNumber partition number over which this query should iterate.
+ *
+ * @return ScanQuery the same instance of the ScanQuery.
+ */
+ public function setPartitionNumber(int $partitionNumber): ScanQuery
+ {
+ $this->partitionNumber = $partitionNumber;
+ return $this;
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function write(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ // filter
+ $communicator->writeObject($buffer, null);
+ $buffer->writeInteger($this->pageSize);
+ $buffer->writeInteger($this->partitionNumber);
+ $buffer->writeBoolean($this->local);
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function getCursor(BinaryCommunicator $communicator, MessageBuffer $payload, $keyType = null, $valueType = null): CursorInterface
+ {
+ $cursor = new Cursor($communicator, ClientOperation::QUERY_SCAN_CURSOR_GET_PAGE, $payload, $keyType, $valueType);
+ $cursor->readId($payload);
+ return $cursor;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsCursorInterface.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsCursorInterface.php b/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsCursorInterface.php
new file mode 100644
index 0000000..77086bb
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsCursorInterface.php
@@ -0,0 +1,82 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Query;
+
+use Apache\Ignite\Type\ObjectType;
+
+/**
+ * Interface representing a cursor to obtain results of SQL Fields query operation.
+ *
+ * An instance of the class with this interface should be obtained via query() method
+ * of an object with CacheInterface.
+ * One instance of the class with SqlFieldsCursorInterface returns results of one SQL Fields query operation.
+ *
+ * SqlFieldsCursorInterface extends CursorInterface which extends the PHP Iterator interface.
+ * The PHP Iterator's methods may be used to obtain the results of the query (arrays with values of the fields)
+ * one by one.
+ * Also, the cursor can be placed into the "foreach" PHP loop to easily iterate over all the results.
+ *
+ * Additionally, SqlFieldsCursorInterface includes
+ * getAll() method to get all the results at once,
+ * getFieldNames() method to return names of the fields,
+ * setFieldTypes() method to specify Ignite types of the fields,
+ * and close() method (defined in CursorInterface) to prematurely close the cursor.
+ *
+ */
+interface SqlFieldsCursorInterface extends CursorInterface
+{
+ /**
+ * Returns all elements (arrays with values of the fields) from the query results at once.
+ *
+ * May be used instead of the PHP Iterator's methods if the number of returned elements
+ * is relatively small and will not cause memory utilization issues.
+ *
+ * @return array all results returned by SQL Fields query.
+ * Every element of the array is an array with values of the fields requested by the query.
+ */
+ public function getAll(): array;
+
+ /**
+ * Returns names of the fields which were requested in the SQL Fields query.
+ *
+ * Empty array is returned if "include field names" flag was false in the query.
+ *
+ * @return array field names.
+ * The order of names corresponds to the order of field values returned in the results of the query.
+ */
+ public function getFieldNames(): array;
+
+ /**
+ * Specifies Ignite types of the fields returned by the SQL Fields query.
+ *
+ * By default, an Ignite type of every field is not specified that means during operations Ignite client
+ * tries to make automatic mapping between PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * @param int|ObjectType|null ...$fieldTypes Ignite types of the returned fields.
+ * The order of types must correspond the order of field values returned in the results of the query.
+ * A type of every field can be:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (or not specified) that means the type is not specified
+ *
+ * @return SqlFieldsCursorInterface the same instance of the class with SqlFieldsCursorInterface.
+ */
+ public function setFieldTypes(...$fieldTypes): SqlFieldsCursorInterface;
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsQuery.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsQuery.php b/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsQuery.php
new file mode 100644
index 0000000..6025c64
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Query/SqlFieldsQuery.php
@@ -0,0 +1,206 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Query;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\ClientOperation;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Query\SqlFieldsCursor;
+
+/**
+ * Class representing an SQL Fields query.
+ */
+class SqlFieldsQuery extends SqlQuery
+{
+ /** @name SqlFieldsQueryStatementType
+ * @anchor SqlFieldsQueryStatementType
+ * @{
+ */
+ const STATEMENT_TYPE_ANY = 0;
+ const STATEMENT_TYPE_SELECT = 1;
+ const STATEMENT_TYPE_UPDATE = 2;
+ /** @} */ // end of SqlFieldsQueryStatementType
+
+ private $schema;
+ private $maxRows;
+ private $statementType;
+ private $enforceJoinOrder;
+ private $collocated;
+ private $lazy;
+ private $includeFieldNames;
+
+ /**
+ * Public constructor.
+ *
+ * Requires SQL query string to be specified.
+ * Other SQL Fields query settings have the following defaults:
+ * <pre>
+ * SQL Fields Query setting : Default value
+ * Local query flag : false
+ * Cursor page size : 1024
+ * Query arguments : not specified
+ * Distributed joins flag : false
+ * Replicated only flag : false
+ * Timeout : 0 (disabled)
+ * Schema for the query : not specified
+ * Max rows : -1
+ * Statement type : STATEMENT_TYPE_ANY
+ * Enforce join order flag : false
+ * Collocated flag : false
+ * Lazy query execution flag : false
+ * Include field names flag : false
+ * </pre>
+ * Every setting may be changed using set methods.
+ *
+ * @param string $sql SQL query string.
+ *
+ * @throws ClientException if error.
+ */
+ public function __construct(string $sql)
+ {
+ parent::__construct(null, $sql);
+ $this->operation = ClientOperation::QUERY_SQL_FIELDS;
+ $this->schema = null;
+ $this->maxRows = -1;
+ $this->statementType = SqlFieldsQuery::STATEMENT_TYPE_ANY;
+ $this->enforceJoinOrder = false;
+ $this->collocated = false;
+ $this->lazy = false;
+ $this->includeFieldNames = false;
+ }
+
+ /**
+ * Set schema for the query.
+ *
+ * @param string $schema schema for the query.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setSchema(string $schema): SqlFieldsQuery
+ {
+ $this->schema = $schema;
+ return $this;
+ }
+
+ /**
+ * Set max rows.
+ *
+ * @param int $maxRows max rows.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setMaxRows(int $maxRows): SqlFieldsQuery
+ {
+ $this->maxRows = $maxRows;
+ return $this;
+ }
+
+ /**
+ * Set statement type.
+ *
+ * @param int $type statement type, one of @ref SqlFieldsQueryStatementType constants.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setStatementType(int $type): SqlFieldsQuery
+ {
+ $this->statementType = $type;
+ return $this;
+ }
+
+ /**
+ * Set enforce join order flag.
+ *
+ * @param bool $enforceJoinOrder enforce join order flag: true or false.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setEnforceJoinOrder(bool $enforceJoinOrder): SqlFieldsQuery
+ {
+ $this->enforceJoinOrder = $enforceJoinOrder;
+ return $this;
+ }
+
+ /**
+ * Set collocated flag.
+ *
+ * @param bool $collocated collocated flag: true or false.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setCollocated(bool $collocated): SqlFieldsQuery
+ {
+ $this->collocated = $collocated;
+ return $this;
+ }
+
+ /**
+ * Set lazy query execution flag.
+ *
+ * @param bool $lazy lazy query execution flag: true or false.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setLazy(bool $lazy): SqlFieldsQuery
+ {
+ $this->lazy = $lazy;
+ return $this;
+ }
+
+ /**
+ * Set include field names flag.
+ *
+ * @param bool $includeFieldNames include field names flag: true or false.
+ *
+ * @return SqlFieldsQuery the same instance of the SqlFieldsQuery.
+ */
+ public function setIncludeFieldNames(bool $includeFieldNames): SqlFieldsQuery
+ {
+ $this->includeFieldNames = $includeFieldNames;
+ return $this;
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function write(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ BinaryCommunicator::writeString($buffer, $this->schema);
+ $buffer->writeInteger($this->pageSize);
+ $buffer->writeInteger($this->maxRows);
+ BinaryCommunicator::writeString($buffer, $this->sql);
+ $this->writeArgs($communicator, $buffer);
+ $buffer->writeByte($this->statementType);
+ $buffer->writeBoolean($this->distributedJoins);
+ $buffer->writeBoolean($this->local);
+ $buffer->writeBoolean($this->replicatedOnly);
+ $buffer->writeBoolean($this->enforceJoinOrder);
+ $buffer->writeBoolean($this->collocated);
+ $buffer->writeBoolean($this->lazy);
+ $buffer->writeLong($this->timeout);
+ $buffer->writeBoolean($this->includeFieldNames);
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function getCursor(BinaryCommunicator $communicator, MessageBuffer $payload, $keyType = null, $valueType = null): CursorInterface
+ {
+ $cursor = new SqlFieldsCursor($communicator, $payload);
+ $cursor->readFieldNames($payload, $this->includeFieldNames);
+ return $cursor;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/7d3ea115/modules/platforms/php/src/Apache/Ignite/Query/SqlQuery.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Query/SqlQuery.php b/modules/platforms/php/src/Apache/Ignite/Query/SqlQuery.php
new file mode 100644
index 0000000..50cc08b
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Query/SqlQuery.php
@@ -0,0 +1,225 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Query;
+
+use Apache\Ignite\Type\ObjectType;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\ClientOperation;
+use Apache\Ignite\Internal\Binary\MessageBuffer;
+use Apache\Ignite\Internal\Binary\BinaryCommunicator;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+use Apache\Ignite\Internal\Query\Cursor;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+
+/**
+ * Class representing an SQL query which returns the whole cache entries (key-value pairs).
+ */
+class SqlQuery extends Query
+{
+ private $args;
+ private $argTypes;
+ protected $sql;
+ protected $type;
+ protected $distributedJoins;
+ protected $replicatedOnly;
+ protected $timeout;
+
+ /**
+ * Public constructor.
+ *
+ * Requires name of a type (or SQL table) and SQL query string to be specified.
+ * Other SQL query settings have the following defaults:
+ * <pre>
+ * SQL Query setting : Default value
+ * Local query flag : false
+ * Cursor page size : 1024
+ * Query arguments : not specified
+ * Distributed joins flag : false
+ * Replicated only flag : false
+ * Timeout : 0 (disabled)
+ * </pre>
+ * Every setting may be changed using set methods.
+ *
+ * @param string $type name of a type or SQL table.
+ * @param string $sql SQL query string.
+ *
+ * @throws ClientException if error.
+ */
+ public function __construct(?string $type, string $sql)
+ {
+ parent::__construct(ClientOperation::QUERY_SQL);
+ $this->setType($type);
+ $this->setSql($sql);
+ $this->args = null;
+ $this->argTypes = null;
+ $this->distributedJoins = false;
+ $this->replicatedOnly = false;
+ $this->timeout = 0;
+ }
+
+ /**
+ * Set name of a type or SQL table.
+ *
+ * @param string $type name of a type or SQL table.
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ *
+ * @throws ClientException if error.
+ */
+ public function setType(?string $type): SqlQuery
+ {
+ if ($this instanceof SqlFieldsQuery) {
+ ArgumentChecker::invalidArgument($type, 'type', SqlFieldsQuery::class);
+ }
+ $this->type = $type;
+ return $this;
+ }
+
+ /**
+ * Set SQL query string.
+ *
+ * @param string $sql SQL query string.
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ */
+ public function setSql(string $sql): SqlQuery
+ {
+ $this->sql = $sql;
+ return $this;
+ }
+
+ /**
+ * Set query arguments.
+ *
+ * Type of any argument may be specified using setArgTypes() method.
+ * If type of an argument is not specified then during operations the Ignite client
+ * will try to make automatic mapping between PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * @param mixed ...$args Query arguments.
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ */
+ public function setArgs(...$args): SqlQuery
+ {
+ $this->args = $args;
+ return $this;
+ }
+
+ /**
+ * Specifies types of query arguments.
+ *
+ * Query arguments itself are set using setArgs() method.
+ * By default, a type of every argument is not specified that means during operations the Ignite client
+ * will try to make automatic mapping between PHP types and Ignite object types -
+ * according to the mapping table defined in the description of the ObjectType class.
+ *
+ * @param int|ObjectType|null ...$argTypes types of Query arguments.
+ * The order of types must follow the order of arguments in the setArgs() method.
+ * A type of every argument can be:
+ * - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+ * - or an instance of class representing non-primitive (composite) type
+ * - or null (or not specified) that means the type is not specified
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ *
+ * @throws ClientException if error.
+ */
+ public function setArgTypes(...$argTypes): SqlQuery
+ {
+ foreach ($argTypes as $argType) {
+ BinaryUtils::checkObjectType($argType, 'argTypes');
+ }
+ $this->argTypes = $argTypes;
+ return $this;
+ }
+
+ /**
+ * Set distributed joins flag.
+ *
+ * @param bool $distributedJoins distributed joins flag: true or false.
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ */
+ public function setDistributedJoins(bool $distributedJoins): SqlQuery
+ {
+ $this->distributedJoins = $distributedJoins;
+ return $this;
+ }
+
+ /**
+ * Set replicated only flag.
+ *
+ * @param bool $replicatedOnly replicated only flag: true or false.
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ */
+ public function setReplicatedOnly(bool $replicatedOnly): SqlQuery
+ {
+ $this->replicatedOnly = $replicatedOnly;
+ return $this;
+ }
+
+ /**
+ * Set timeout.
+ *
+ * @param float $timeout timeout value in milliseconds.
+ * Must be non-negative. Zero value disables timeout.
+ *
+ * @return SqlQuery the same instance of the SqlQuery.
+ */
+ public function setTimeout(float $timeout): SqlQuery
+ {
+ $this->timeout = $timeout;
+ return $this;
+ }
+
+ protected function writeArgs(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ $argsLength = $this->args ? count($this->args) : 0;
+ $buffer->writeInteger($argsLength);
+ if ($argsLength > 0) {
+ for ($i = 0; $i < $argsLength; $i++) {
+ $argType = $this->argTypes && $i < count($this->argTypes) ? $this->argTypes[$i] : null;
+ $communicator->writeObject($buffer, $this->args[$i], $argType);
+ }
+ }
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function write(BinaryCommunicator $communicator, MessageBuffer $buffer): void
+ {
+ BinaryCommunicator::writeString($buffer, $this->type);
+ BinaryCommunicator::writeString($buffer, $this->sql);
+ $this->writeArgs($communicator, $buffer);
+ $buffer->writeBoolean($this->distributedJoins);
+ $buffer->writeBoolean($this->local);
+ $buffer->writeBoolean($this->replicatedOnly);
+ $buffer->writeInteger($this->pageSize);
+ $buffer->writeLong($this->timeout);
+ }
+
+ // This is not the public API method, is not intended for usage by an application.
+ public function getCursor(BinaryCommunicator $communicator, MessageBuffer $payload, $keyType = null, $valueType = null): CursorInterface
+ {
+ $cursor = new Cursor($communicator, ClientOperation::QUERY_SQL_CURSOR_GET_PAGE, $payload, $keyType, $valueType);
+ $cursor->readId($payload);
+ return $cursor;
+ }
+}