Unfortunately `VEMB` has a unique `RESP2` reply as far as I can tell,
where it sends the embedding mode (int8, bin, fp32) as a simple string.
This would cause any of PhpRedis' generic reply handlers to turn that
into `true` which isn't useful. For that reason we need a custom reply
handler.
Additionally slightly rework `VINFO` to short circuit and return failure
if we read anything other than a bulk string or an integer reply type.
Otherwise we may get out of sync on the socket.
See #2543
All of these commands have the same form `<cmd> key`. `VINFO` is a bit
of an outlier however that uses simple strings as opposed to bulk
strings for the key names, meaning we had to create a custom handler.
See #2543
This command is similar to `VADD` in that it's pretty simple but allows
for a great many options.
In it's most basic form:
```php
// To get similarity of a different element
$redis->vsim('myvec', 'some-element');
// To get similarity for a vector of scores
```
As seen above the method attempts to infer element or vector from the
argument passed to $member`. However, since we do serialize the member
when doing `ELE` mode, the user can also specify `ELE` explicitly in the
options array to force an `ELE` search sending serialized values.
```php
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
$redis->vsim('myvec', [3.14, 2.71], ['ELE']);
```
See #2543
This is for Redis 8.0's vector sets.
The command itself can be quite complex with all of the various options but
pretty simple using all defaults.
```php
$redis->vadd('myvec', [3.14, 2.17], 'myelement');
```
The implementation takes a default argument `$options` which can be an array in
order to specify the myriad of other knobs users can send. We just do a bit of
validation on inputs (e.g. certain numeric options must be positive) and make
sure the command is constructed in a valid way (e.g. REDUCE <dim> must come
before the floating point values).
By default we deliver `FP32` blobs but allow the user to send `VALUES` in the
options array which will cause PhpRedis to send N individual values. Sending
values is slower but might be nice for debugging (e.g. watching monitor)
See #2543
* Rework HMGET and implement HGETEX
Instead of using a bespoke NULL terminated `zval**` array for the
context array we can use a `HashTable`. This might be a tiny bit more
expensive but Zend hashtables are quite efficient and this should also
be less error prone.
* Rework our `HashTable` context array to store keys
Instead of sending an array of values we can instead add the fields as
keys to our context array. That way when we combine the keys with the
Redis provided values we can do it in-place and then just give the
HashTable to the user to then do with what they want.
* Implement HGETDEL command.
* Fix edge cases to abide by legacy behavior.
Previously we coerced integer strings into integer keys when zipping
`HMGET` responses. This commit adds logic so we continue to do this and
do not change semantics.
* Implement `HGETDEL` and `HGETEX` for `RedisCluster`.
This commit implements the new commands and reworks the `HMGET` reply
handler to use the new context `HashTable`.
* Fix an edge case where we get zero multiblk elements
* Tests for `HGETEX` and `HGETDEL`
* Minor logic improvement
We don't need to check if `c->reply_len > 0` in the last else block
since we have already determined it must be.
* Implement `HSETEX` for `Redis` and `RedisCluster`
* Use `zval_get_tmp_string` ro populating non-long keys
`Redis::hGetAll()` returns an array indexed by `string`s and/or `int`s depending on the values in the hash set.
The function in the PHP stub was annotated as though the array were keyed only by strings, which is tighter than reality.
Right now we can't implement `HELLO` command to switch protocol
because we don't support new reply types that come with RESP3.
But we can use `HELLO` reply to expose some server information.
Adds an option that instructs PhpRedis to not serialize or compress
numeric values. Specifically where `Z_TYPE_P(z) == IS_LONG` or
`Z_TYPE_P(z) == IS_DOUBLE`.
This flag lets the user enable serialization and/or compression while
still using the various increment/decrement command (`INCR`, `INCRBY`,
`DECR`, `DECRBY`, `INCRBYFLOAT`, `HINCRBY`, and `HINCRBYFLOAT`).
Because PhpRedis can't be certain that this option was enabled when
writing keys, there is a small runtime cost on the read-side that tests
whether or not the value its reading is a pure integer or floating point
value.
See #23
Redis requires the user to send a count if `WITHVALUES` is specified,
otherwise it sees the `WITHVALUES` argument as the count and will error
out that it's not a number.
We can also return false if the key doesn't exist.
Technically Redis may return any unsigned 64 bit integer as a scan
cursor. This presents a problem for PHP in that PHP's integers are
signed. Because of that if a scan cursor is > 2^63 it will overflow and
fail to work properly.
This commit updates our SCAN family of commands to deliver cursors in
their string form.
```php
public function scan(null|int|string $iterator, ...);
```
On initial entry into our SCAN family we convert either a NULL or empty
string cursor to zero, and send the initial scan command.
As Redis replies with cursors we either represent them as a long (if
they are <= ZEND_ULONG_MAX) and as a string if greater. This should
mean the fix is minimally breaking as the following code will still
work:
```php
$it = NULL;
do {
print_r($redis->scan($it));
} while ($it !== 0);
```
The `$it !== 0` still works because the zero cursor will be represented
as an integer. Only absurdly large (> 2^63) values are represented as a
string.
Fixes#2454
* Use our `redis_cmd_append_sstr_key_*` and `redis_cmd_append_sstr_zval`
wrappers, which handle key prefixing and serialization transparently.
* Rework ZADD so it can handle the bulk double response from the `INCR`
options.
Rework argument parsing for `ZRANGE` so we can pass either a string or
an integer so everything will work even when using strict types.
Additionally update our docs to use the correct mechanism for adding
the `BYSCORE` option.
Fixes#2291
* Create inline wrappers of the low-level php_stream_* functions that
also keep track of the number of bytes written/read.
* Change the logic to aggregate network traffic until the user
explicitly "resets" it. I think this will be a more common use-case
(running many commands and then seeing overall network IO).
See #2106
Let gen_stub.php define the constants for us, including deriving their
actual values from C defines.
As a side-effect we have to drop support for PHP < 7.2 as it does not
have interned strings.