358 Commits

Author SHA1 Message Date
michael-grunder
6ce3bd533a Implement VRANGE command and add a test 2025-10-02 11:12:39 -07:00
michael-grunder
35df8ad7c2 Attempt to fix an overflow bug in ZADD on Windows
Theory: In 64 bit windows `long` is 32 bits wide meaning that using a
long to append `ZADD` scores can truncate.

Possible fix for #2697
2025-09-09 16:30:43 -07:00
michael-grunder
b8de91c9e0 Fix errors and a warning
* PHP < 8.0 took a `char*` as `php_json_decode` input, whereas newer
  versions take a const char * so ifdef around this.

* Fix compilation errors due to `false` not being defined. So as to make
  a minimal change we can just use 0 and 1
2025-09-01 09:41:12 -07:00
michael-grunder
d80b725824 Implement VGETATTR command 2025-09-01 09:41:12 -07:00
michael-grunder
7f9b1f416e Implement VLINKS command 2025-09-01 09:41:12 -07:00
michael-grunder
92716ed0c5 Implement VSETATTR command 2025-09-01 09:41:12 -07:00
michael-grunder
65927b53b1 We can use redis_kv_cmd instead of a specific vrem command. 2025-09-01 09:41:12 -07:00
michael-grunder
dc91631b3f Implement VREM command
See #2543
2025-09-01 09:41:12 -07:00
michael-grunder
1deca62841 Implement VRANDMEMBER
`VRANDMEMBER` has the exact same semantics of `SRANDMEMBER` so make
`SRANDMEMBER` a keyword based command and use it for `VRANDMEMBER`.

See #2543
2025-09-01 09:41:12 -07:00
michael-grunder
96378b70fd Implement VEMB and slightly rework VINFO
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
2025-09-01 09:41:12 -07:00
michael-grunder
659dc763e0 Refactor redis_replicaof_cmd
It was the last place we were using `REDIS_SPPRINTF` in
`redis_commands.c`.
2025-08-27 16:37:08 -07:00
michael-grunder
8d369f4d62 Implement GEOSEARCH[STORE] BYPOLYGON.
Valkey 9.0.0 implemented a new variant of `GEOSEARCH` where you supply
the verticies to an arbitrary polygon.

Since we can't modify the `geosearch` prototype using it is a little
wonky (you need to just pass empty strings for position and unit).

```php
$redis->geosearch('ca:cities', '', [
    -121.90, 39.65, -121.77, 39.65, -121.77, 39.80, -121.90, 39.80
], '');
$redis->geosearchstore('ca:cities', 'dst', '', [
    -121.90, 39.65, -121.77, 39.65, -121.77, 39.80, -121.90, 39.80
], '');
```
2025-08-24 06:37:51 -07:00
michael-grunder
f4ec5e2bb0 Use ZEND_STRL instead of literal, len 2025-08-21 08:53:51 -07:00
michael-grunder
03837f0230 Remove pointless casts
You never have to explicitly cast between `void*` and any other pointer
type.
2025-08-21 08:53:51 -07:00
michael-grunder
d564e8cf3c Fix dead assignment 2025-08-21 08:53:51 -07:00
michael-grunder
6e5faf4226 Refactor EVAL[SHA] command and add a regression test
* We can make the code simpler by using `zend_empty_array` when no args
  are passed as well as the new argument parsing macros and newer internal
  redis command appending functions that take zend strings.

* Add a regression test for when we execute `EVAL[SHA]` with arguments
  but do not send any keys. This was causing UB in RedisCluster (#2681).
2025-08-05 13:20:36 -07:00
michael-grunder
f61e8cd7ba Fix RedisCluster segfault
We were previously only picking a random slot if the user didn't pass
any arguments at all whereas we want to pick a random slot if they don't
pass any *keys*.

This change just universally picks a random slot at the beginning and
then if any keys are processed those keys will override the random
selection.

Fixes #2681
2025-08-05 08:28:43 -07:00
michael-grunder
d1d690053f Implement VSIM command
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
2025-07-31 08:30:47 -07:00
michael-grunder
286fa63064 Implement VADD command
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
2025-07-31 00:57:28 -07:00
michael-grunder
ca80ee0e67 Fix passing NULL for hash expiry argument
The stubs specify `?string $mode = NULL` but we were using `Z_PARAM_STR`
causing an arginfo mismatch.

Fixes #2674
2025-07-28 10:33:49 -07:00
Pavlo Yatsukhnenko
a6922a07fe Update redis_commands.c
Co-authored-by: Michael Grunder <michael.grunder@gmail.com>
2025-07-24 09:38:01 -07:00
Pavlo Yatsukhnenko
6b2f088d49 Fix hset fields handling 2025-07-24 09:38:01 -07:00
Pavlo Yatsukhnenko
7805da7542 Fix HSetEx expiry argument handling 2025-07-24 09:08:33 -07:00
Michael Grunder
ce5b0facc2 Implement HGETEX, HSETEX, HGETDEL, and refactor HMGET (#2667)
* 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
2025-07-16 16:46:09 -07:00
michael-grunder
7350768cd9 Implement several hash expiration commands
Commands implemented:

`H[P]EXPIRE`
`H[P]TTL`
`H[P]EXPIREAT`
`H[P]EXPIRETIME`
`HPERSIST`
2025-05-07 08:16:14 -07:00
Jakub Onderka
0a85bd824a Simplify redis_unpack method calling
This method always unpack given string to zval, so it is not necessary to check output value
2025-04-02 13:02:52 -07:00
Pavlo Yatsukhnenko
f73f5fcce5 Fix arguments order for SET command
Redis and Valkey doesn't consider command as invalid if order of arguments
is changed but other servers like DragonflyDB does.
In this commit `SET` command is fixed to more strictly follow the specs.
Also fixed usage of `zend_tmp_string` for `ifeq` argument.
2025-03-16 12:10:53 -07:00
michael-grunder
f9ce9429ef Introduce Redis::OPT_PACK_IGNORE_NUMBERS option.
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
2025-02-05 14:12:42 -08:00
michael-grunder
a2eef77f44 Implement Valkey >= 8.1 IFEQ set option
Implement the new `IFEQ` `SET` option that will be included in `Valkey`
8.1.

See: valkey-io/valkey#1324
2025-01-20 08:04:27 -08:00
Bentley O'Kane-Chase
35c5988027 Formatting improvements 2024-12-17 17:08:36 -08:00
Bentley O'Kane-Chase
138d07b67c Print cursor as unsigned 64 bit integer 2024-12-17 17:08:36 -08:00
Jakub Onderka
aba09933db Avoid unnecessary allocation in redis_hset_cmd
This will slightly reduce memory usage for HSET command
2024-11-26 18:28:09 -08:00
Jakub Onderka
4082dd07f7 Avoid unnecessary allocation in redis_hdel_cmd
This will slightly reduce memory usage for HDEL command
2024-11-26 18:28:09 -08:00
Jakub Onderka
99650e1545 Avoid unnecessary allocation in redis_key_varval_cmd
This will slightly reduce memory usage for commands like RPUSH, LPUSH, SADD, SREM, etc
2024-11-26 18:28:09 -08:00
Jakub Onderka
f6906470a5 Use zval_get_tmp_string method that is faster when provided zval is string 2024-11-26 18:28:09 -08:00
Jakub Onderka
83a19656f4 Faster parameter parsing in redis_key_cmd and redis_key_long_val_cmd 2024-11-26 10:39:23 -08:00
michael-grunder
4cd3f59356 Implement KeyDB's EXPIREMEMBER[AT] commands 2024-11-15 08:59:10 -08:00
michael-grunder
0fe45d24d4 Fix XAUTOCLAIM argc when sending COUNT
Add 2 to argc not 1 + count when sending a specific COUNT.
2024-10-17 08:21:54 -07:00
Viktor Djupsjöbacka
6ea5b3e08b Fix argument count issue in HSET with associative array, update method signature for HSET and add documentation 2024-07-17 12:47:49 -07:00
Michael Grunder
99f9fd8353 Fix HRANDFIELD command when WITHVALUES is used. (#2524)
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.
2024-07-13 22:42:25 -07:00
michael-grunder
981c69314d Add GETEX to README docs + minor change to command.
* Adds `GETEX` to the README.md documentation.
* Allow the user to send `PERSIST` either as an array key or just in the
  array, to conform with similar methods.
* Implement getEx for `RedisCluster`

Fixes #2512
2024-06-20 13:56:17 -07:00
Pavlo Yatsukhnenko
7c551424b6 Refactor redis_script_cmd
- Update redis_script_cmd to use redis_build_script_cmd.
- Fix condition for parsing sync/async arguments of flush sub-command.
2024-06-20 21:05:20 +03:00
michael-grunder
fa1a283ac9 Fix some typos 2024-03-13 13:46:58 -07:00
michael-grunder
732e466a6a Improve warning when we encounter an invalid EXPIRY in SET
We actually had two different bits of logic to handle EXPIRY values in
the `SET` command.  One for the legacy `SET` -> `SETEX` mapping and
another for the newer `SET foo bar EX <expiry>`.

Additionally the error message could be confusing.  Passing 3.1415 for
an `EX` expiry would fail as we didn't allow floats.

This commit consolidates expiry parsing to our existing helper function
as well as improves the `php_error_docref` warning in the event that the
user passes invalid data.  The warning will now tell the user the type
they tried to pass as an EXPIRY to make it easier to track down what's
going wrong.

Fixes #2448
2024-02-21 13:16:36 -08:00
Viktor Szépe
37c5f8d451 Fix typos 2024-02-21 13:16:12 -08:00
michael-grunder
ed7c9f6f63 Implement WAITAOF command. 2024-02-14 12:03:29 -08:00
michael-grunder
2f276dcd37 Find our callback by pattern with PSUBSCRIBE
* Use the pattern Redis provides us not the channel, if this is
a wildcard based `PSUBSCRIBE` payload.

* Don't test whether our slots match in `SSUBSCRIBE` when not in cluster
  mode.

Fixes #2395
2023-09-26 11:29:04 -07:00
Pavlo Yatsukhnenko
264c0c7ea4 Fix unknown expiration modifier warning when null argument passed 2023-09-17 10:17:05 +03:00
Remi Collet
715012b2c1 fix C99 usages 2023-08-02 16:07:21 +02:00
michael-grunder
ccd419a4c8 Small refactor of some methods
* 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.
2023-03-01 11:45:47 -08:00