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 wrapper macro implicitly defines an `} else {` block but this is
not clear at the callsite which obsures what is actually going on.
There's no real advantage to the wrapping macro. Instead just call the
underlying macro in an explicit else branch.
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
DragonflyDB will report to be Redis but also include `dragonfly_version`
in the hello response, which we can use to identify the fork.
Also fix parsing of the `HELLO` response for `serverName()` and
`serverVersion()`. Starting in Redis 8.0 there seem to always be modules
running, which the previous function was not expecting or parsing.
* New option 'database' for Redis class constructor
Selecting database is very common action after connecting to Redis. This simplifies lazy connecting to Redis, when requested database will be selected after first command.
* More specific exception message when invalid auth or database number is provided
Before it was just 'Redis server went away'
* Rename reselect_db method to redis_select_db and slightly optimise it
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.
We recently updated PhpRedis to handle `SCAN` cursors > 2^63 as strings
(as internally PHP integers are longs).
However, the `redis_build_scan_cmd` took the cursor as a long, which
would overflow if the value was > `2^63`.
This commit simply changes the function to take a `uint64_t` and call
our specific `redis_append_sstr_u64` so we send the cursor to Redis
correctly.
Fixes#2454.
On some glibc implementations strncmp is a macro. This commit simply creates a
`redis_strncmp` static inline wrapper function so we can `ZEND_STRL` instead of
manually counting the length or using `sizeof(s)-1` each time.
Fixes#2565
* Add compression support for PHP Sessions
Previously, compression was available for standard data but not for
session handling. This update enables the compression of PHP sessions,
allowing for more efficient Redis memory usage.
* Move session compress/uncompress logic to helper functions
* Change session_compress_data to always set the out arguments and adjust PS_READ_FUNC
Replace `SOCKET_WRITE_COMMAND` with `redis_sock_write` because it can't be used
with pre-defined commands (it frees memory in case of failed writing operation).
After replacement `SOCKET_WRITE_COMMAND` becomes redundant so remove it.
PHP 8.4 has some breaking changes with respect to where PHP's random methods and
helpers are. This commit fixes those issues while staying backward compatible.
Fixes#2463
We also need to update the `RedisCluster` logic to handle very large
curosr values, in addition to handling them for the `Redis` and
`RedisArray` classes.
See #2454, #2458
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