Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 71bcbcb

Browse files
Implement ZRANGESTORE and add ZRANGE options
* Add ZRANGESTORE command. * Add Redis 6.2's `REV`, `BYLEX`, and `BYSCORE` to ZRANGE options. * Refactor several ZRANGE family commands into a single reply and options handler, using PHP's new argument parsing macros. * Extend our tests to use the new ZRANGE options. See #1894
1 parent f3a4083 commit 71bcbcb

15 files changed

Lines changed: 386 additions & 232 deletions

cluster_library.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,6 +2115,17 @@ cluster_variant_resp_generic(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
21152115
cluster_free_reply(r, 1);
21162116
}
21172117

2118+
PHP_REDIS_API void
2119+
cluster_zrange_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
2120+
cluster_cb cb;
2121+
2122+
ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
2123+
2124+
cb = ctx ? cluster_mbulk_zipdbl_resp : cluster_mbulk_resp;
2125+
2126+
cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
2127+
}
2128+
21182129
PHP_REDIS_API void cluster_variant_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
21192130
void *ctx)
21202131
{

cluster_library.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,9 @@ PHP_REDIS_API void cluster_sub_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *
437437
PHP_REDIS_API void cluster_unsub_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
438438
void *ctx);
439439

440+
PHP_REDIS_API void cluster_zrange_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
441+
void *ctx);
442+
440443
PHP_REDIS_API void cluster_variant_resp(INTERNAL_FUNCTION_PARAMETERS,
441444
redisCluster *c, void *ctx);
442445

library.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,18 @@ redis_config_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval
11601160
return cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, ctx);
11611161
}
11621162

1163+
PHP_REDIS_API int
1164+
redis_zrange_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
1165+
FailableResultCallback cb;
1166+
1167+
/* Whether or not we have WITHSCORES */
1168+
ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
1169+
1170+
cb = ctx ? redis_mbulk_reply_zipped_keys_dbl : redis_sock_read_multibulk_reply;
1171+
1172+
return cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, ctx);
1173+
}
1174+
11631175
PHP_REDIS_API int redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
11641176
char *response;
11651177
int response_len;

library.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ PHP_REDIS_API int redis_string_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock
6868
PHP_REDIS_API int redis_ping_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
6969
PHP_REDIS_API int redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
7070
PHP_REDIS_API int redis_config_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
71+
PHP_REDIS_API int redis_zrange_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
7172
PHP_REDIS_API void redis_parse_info_response(char *response, zval *z_ret);
7273
PHP_REDIS_API void redis_parse_client_list_response(char *response, zval *z_ret);
7374
PHP_REDIS_API int redis_type_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);

redis.c

Lines changed: 10 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,77 +1906,38 @@ PHP_METHOD(Redis, zAdd) {
19061906
}
19071907
/* }}} */
19081908

1909-
/* Handle ZRANGE and ZREVRANGE as they're the same except for keyword */
1910-
static void generic_zrange_cmd(INTERNAL_FUNCTION_PARAMETERS, char *kw,
1911-
zrange_cb fun)
1912-
{
1913-
char *cmd;
1914-
int cmd_len;
1915-
RedisSock *redis_sock;
1916-
int withscores = 0;
1917-
1918-
if ((redis_sock = redis_sock_get(getThis(), 0)) == NULL) {
1919-
RETURN_FALSE;
1920-
}
1921-
1922-
if(fun(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, kw, &cmd,
1923-
&cmd_len, &withscores, NULL, NULL) == FAILURE)
1924-
{
1925-
RETURN_FALSE;
1926-
}
1927-
1928-
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
1929-
if(withscores) {
1930-
if (IS_ATOMIC(redis_sock)) {
1931-
redis_mbulk_reply_zipped_keys_dbl(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL);
1932-
}
1933-
REDIS_PROCESS_RESPONSE(redis_mbulk_reply_zipped_keys_dbl);
1934-
} else {
1935-
if (IS_ATOMIC(redis_sock)) {
1936-
if(redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU,
1937-
redis_sock, NULL, NULL) < 0)
1938-
{
1939-
RETURN_FALSE;
1940-
}
1941-
}
1942-
REDIS_PROCESS_RESPONSE(redis_sock_read_multibulk_reply);
1943-
}
1944-
}
1945-
19461909
/* {{{ proto array Redis::zRandMember(string key, array options) */
1947-
PHP_METHOD(Redis, zRandMember)
1948-
{
1910+
PHP_METHOD(Redis, zRandMember) {
19491911
REDIS_PROCESS_CMD(zrandmember, redis_zrandmember_response);
19501912
}
19511913
/* }}} */
19521914

19531915
/* {{{ proto array Redis::zRange(string key,int start,int end,bool scores = 0) */
1954-
PHP_METHOD(Redis, zRange)
1955-
{
1956-
generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZRANGE",
1957-
redis_zrange_cmd);
1916+
PHP_METHOD(Redis, zRange) {
1917+
REDIS_PROCESS_KW_CMD("ZRANGE", redis_zrange_cmd, redis_zrange_response);
19581918
}
19591919
/* }}} */
19601920

1921+
PHP_METHOD(Redis, zrangestore) {
1922+
REDIS_PROCESS_KW_CMD("ZRANGESTORE", redis_zrange_cmd, redis_long_response);
1923+
}
1924+
19611925
/* {{{ proto array Redis::zRevRange(string k, long s, long e, bool scores = 0) */
19621926
PHP_METHOD(Redis, zRevRange) {
1963-
generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZREVRANGE",
1964-
redis_zrange_cmd);
1927+
REDIS_PROCESS_KW_CMD("ZREVRANGE", redis_zrange_cmd, redis_zrange_response);
19651928
}
19661929
/* }}} */
19671930

19681931
/* {{{ proto array Redis::zRangeByScore(string k,string s,string e,array opt) */
19691932
PHP_METHOD(Redis, zRangeByScore) {
1970-
generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZRANGEBYSCORE",
1971-
redis_zrangebyscore_cmd);
1933+
REDIS_PROCESS_KW_CMD("ZRANGEBYSCORE", redis_zrange_cmd, redis_zrange_response);
19721934
}
19731935
/* }}} */
19741936

19751937
/* {{{ proto array Redis::zRevRangeByScore(string key, string start, string end,
19761938
* array options) */
19771939
PHP_METHOD(Redis, zRevRangeByScore) {
1978-
generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZREVRANGEBYSCORE",
1979-
redis_zrangebyscore_cmd);
1940+
REDIS_PROCESS_KW_CMD("ZREVRANGEBYSCORE", redis_zrange_cmd, redis_zrange_response);
19801941
}
19811942
/* }}} */
19821943

redis.stub.php

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,12 +694,68 @@ public function zPopMax(string $key, int $value = null): Redis|array|false;
694694

695695
public function zPopMin(string $key, int $value = null): Redis|array|false;
696696

697-
public function zRange(string $key, int $start, int $end, mixed $scores = null): Redis|array|false;
697+
/**
698+
* Retreive a range of elements of a sorted set between a start and end point.
699+
* How the command works in particular is greatly affected by the options that
700+
* are passed in.
701+
*
702+
* @see https://https://redis.io/commands/zrange/
703+
* @category zset
704+
*
705+
* @param string $key The sorted set in question.
706+
* @param mixed $start The starting index we want to return.
707+
* @param mixed $end The final index we want to return.
708+
*
709+
* @param array|bool|null $options This value may either be an array of options to pass to
710+
* the command, or for historical purposes a boolean which
711+
* controls just the 'WITHSCORES' option.
712+
*
713+
* @return Redis|array|false An array with matching elements or false on failure.
714+
*
715+
* Detailed description of options array:
716+
*
717+
* <code>
718+
* <?php
719+
* $options = [
720+
* 'WITHSCORES' => true, // Return both scores and members.
721+
* 'LIMIT' => [10, 10], // Start at offset 10 and return 10 elements.
722+
* 'REV' // Return the elements in reverse order
723+
* 'BYSCORE', // Treat `start` and `end` as scores instead
724+
* 'BYLEX' // Treat `start` and `end` as lexographical values.
725+
* ];
726+
* ?>
727+
* </code>
728+
*
729+
* Note: 'BYLEX' and 'BYSCORE' are mutually exclusive.
730+
*
731+
*/
732+
public function zRange(string $key, mixed $start, mixed $end, array|bool|null $options = null): Redis|array|false;
698733

699734
public function zRangeByLex(string $key, string $min, string $max, int $offset = -1, int $count = -1): Redis|array|false;
700735

701736
public function zRangeByScore(string $key, string $start, string $end, array $options = []): Redis|array|false;
702737

738+
/**
739+
* This command is similar to ZRANGE except that instead of returning the values directly
740+
* it will store them in a destination key provided by the user
741+
*
742+
* @see https://https://redis.io/commands/zrange/
743+
* @see Redis::zRange
744+
* @category zset
745+
*
746+
* @param string $dstkey The key to store the resulting element(s)
747+
* @param string $srckey The source key with element(s) to retreive
748+
* @param string $start The starting index to store
749+
* @param string $end The ending index to store
750+
* @param array|bool|null $options Our options array that controls how the command will function.
751+
*
752+
* @return Redis|int|false The number of elements stored in dstkey or false on failure.
753+
*
754+
* See Redis::zRange for a full description of the possible options.
755+
*/
756+
public function zrangestore(string $dstkey, string $srckey, string $start, string $end,
757+
array|bool|null $options = NULL): Redis|int|false;
758+
703759
public function zRandMember(string $key, array $options = null): Redis|string|array;
704760

705761
public function zRank(string $key, mixed $member): Redis|int|false;

redis_arginfo.h

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: a27d28648f2d1a77237305083f36abc5e071f5b1 */
2+
* Stub hash: 73bbd79b67c155a90acfa2b5ca1be49effdaf8ba */
33

44
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0)
55
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "null")
@@ -1000,9 +1000,9 @@ ZEND_END_ARG_INFO()
10001000

10011001
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRange, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
10021002
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
1003-
ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
1004-
ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
1005-
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, scores, IS_MIXED, 0, "null")
1003+
ZEND_ARG_TYPE_INFO(0, start, IS_MIXED, 0)
1004+
ZEND_ARG_TYPE_INFO(0, end, IS_MIXED, 0)
1005+
ZEND_ARG_TYPE_MASK(0, options, MAY_BE_ARRAY|MAY_BE_BOOL|MAY_BE_NULL, "null")
10061006
ZEND_END_ARG_INFO()
10071007

10081008
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRangeByLex, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
@@ -1020,6 +1020,14 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRangeByScore, 0
10201020
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
10211021
ZEND_END_ARG_INFO()
10221022

1023+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zrangestore, 0, 4, Redis, MAY_BE_LONG|MAY_BE_FALSE)
1024+
ZEND_ARG_TYPE_INFO(0, dstkey, IS_STRING, 0)
1025+
ZEND_ARG_TYPE_INFO(0, srckey, IS_STRING, 0)
1026+
ZEND_ARG_TYPE_INFO(0, start, IS_STRING, 0)
1027+
ZEND_ARG_TYPE_INFO(0, end, IS_STRING, 0)
1028+
ZEND_ARG_TYPE_MASK(0, options, MAY_BE_ARRAY|MAY_BE_BOOL|MAY_BE_NULL, "NULL")
1029+
ZEND_END_ARG_INFO()
1030+
10231031
#define arginfo_class_Redis_zRandMember arginfo_class_Redis_hRandField
10241032

10251033
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRank, 0, 2, Redis, MAY_BE_LONG|MAY_BE_FALSE)
@@ -1043,7 +1051,12 @@ ZEND_END_ARG_INFO()
10431051

10441052
#define arginfo_class_Redis_zRemRangeByScore arginfo_class_Redis_zCount
10451053

1046-
#define arginfo_class_Redis_zRevRange arginfo_class_Redis_zRange
1054+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRevRange, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
1055+
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
1056+
ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
1057+
ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
1058+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, scores, IS_MIXED, 0, "null")
1059+
ZEND_END_ARG_INFO()
10471060

10481061
#define arginfo_class_Redis_zRevRangeByLex arginfo_class_Redis_zRangeByLex
10491062

@@ -1314,6 +1327,7 @@ ZEND_METHOD(Redis, zPopMin);
13141327
ZEND_METHOD(Redis, zRange);
13151328
ZEND_METHOD(Redis, zRangeByLex);
13161329
ZEND_METHOD(Redis, zRangeByScore);
1330+
ZEND_METHOD(Redis, zrangestore);
13171331
ZEND_METHOD(Redis, zRandMember);
13181332
ZEND_METHOD(Redis, zRank);
13191333
ZEND_METHOD(Redis, zRem);
@@ -1559,6 +1573,7 @@ static const zend_function_entry class_Redis_methods[] = {
15591573
ZEND_ME(Redis, zRange, arginfo_class_Redis_zRange, ZEND_ACC_PUBLIC)
15601574
ZEND_ME(Redis, zRangeByLex, arginfo_class_Redis_zRangeByLex, ZEND_ACC_PUBLIC)
15611575
ZEND_ME(Redis, zRangeByScore, arginfo_class_Redis_zRangeByScore, ZEND_ACC_PUBLIC)
1576+
ZEND_ME(Redis, zrangestore, arginfo_class_Redis_zrangestore, ZEND_ACC_PUBLIC)
15621577
ZEND_ME(Redis, zRandMember, arginfo_class_Redis_zRandMember, ZEND_ACC_PUBLIC)
15631578
ZEND_ME(Redis, zRank, arginfo_class_Redis_zRank, ZEND_ACC_PUBLIC)
15641579
ZEND_ME(Redis, zRem, arginfo_class_Redis_zRem, ZEND_ACC_PUBLIC)

redis_cluster.c

Lines changed: 11 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,61 +1429,31 @@ PHP_METHOD(RedisCluster, setrange) {
14291429
}
14301430
/* }}} */
14311431

1432-
/* Generic implementation for ZRANGE, ZREVRANGE, ZRANGEBYSCORE, ZREVRANGEBYSCORE */
1433-
static void generic_zrange_cmd(INTERNAL_FUNCTION_PARAMETERS, char *kw,
1434-
zrange_cb fun)
1435-
{
1436-
redisCluster *c = GET_CONTEXT();
1437-
c->readonly = CLUSTER_IS_ATOMIC(c);
1438-
cluster_cb cb;
1439-
char *cmd; int cmd_len; short slot;
1440-
int withscores = 0;
1441-
1442-
if (fun(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags, kw, &cmd, &cmd_len,
1443-
&withscores, &slot, NULL) == FAILURE)
1444-
{
1445-
efree(cmd);
1446-
RETURN_FALSE;
1447-
}
1448-
1449-
if (cluster_send_command(c,slot,cmd,cmd_len) < 0 || c->err != NULL) {
1450-
efree(cmd);
1451-
RETURN_FALSE;
1452-
}
1453-
1454-
efree(cmd);
1455-
1456-
cb = withscores ? cluster_mbulk_zipdbl_resp : cluster_mbulk_resp;
1457-
if (CLUSTER_IS_ATOMIC(c)) {
1458-
cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
1459-
} else {
1460-
void *ctx = NULL;
1461-
CLUSTER_ENQUEUE_RESPONSE(c, slot, cb, ctx);
1462-
RETURN_ZVAL(getThis(), 1, 0);
1463-
}
1464-
}
1465-
14661432
/* {{{ proto
14671433
* array RedisCluster::zrange(string k, long s, long e, bool score = 0) */
14681434
PHP_METHOD(RedisCluster, zrange) {
1469-
generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZRANGE",
1470-
redis_zrange_cmd);
1435+
CLUSTER_PROCESS_KW_CMD("ZRANGE", redis_zrange_cmd, cluster_zrange_resp, 1);
14711436
}
14721437
/* }}} */
14731438

1439+
/* {{{ proto
1440+
* array RedisCluster::zrange(string $dstkey, string $srckey, long s, long e, array|bool $options = false) */
1441+
PHP_METHOD(RedisCluster, zrangestore) {
1442+
CLUSTER_PROCESS_KW_CMD("ZRANGESTORE", redis_zrange_cmd, cluster_long_resp, 0);
1443+
}
1444+
1445+
/* }}} */
14741446
/* {{{ proto
14751447
* array RedisCluster::zrevrange(string k,long s,long e,bool scores = 0) */
14761448
PHP_METHOD(RedisCluster, zrevrange) {
1477-
generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZREVRANGE",
1478-
redis_zrange_cmd);
1449+
CLUSTER_PROCESS_KW_CMD("ZREVRANGE", redis_zrange_cmd, cluster_zrange_resp, 1);
14791450
}
14801451
/* }}} */
14811452

14821453
/* {{{ proto array
14831454
* RedisCluster::zrangebyscore(string k, long s, long e, array opts) */
14841455
PHP_METHOD(RedisCluster, zrangebyscore) {
1485-
generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZRANGEBYSCORE",
1486-
redis_zrangebyscore_cmd);
1456+
CLUSTER_PROCESS_KW_CMD("ZRANGEBYSCORE", redis_zrange_cmd, cluster_zrange_resp, 1);
14871457
}
14881458
/* }}} */
14891459

@@ -1516,8 +1486,7 @@ PHP_METHOD(RedisCluster, zrem) {
15161486
/* {{{ proto array
15171487
* RedisCluster::zrevrangebyscore(string k, long s, long e, array opts) */
15181488
PHP_METHOD(RedisCluster, zrevrangebyscore) {
1519-
generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZREVRANGEBYSCORE",
1520-
redis_zrangebyscore_cmd);
1489+
CLUSTER_PROCESS_KW_CMD("ZREVRANGEBYSCORE", redis_zrange_cmd, cluster_zrange_resp, 1);
15211490
}
15221491
/* }}} */
15231492

redis_cluster.stub.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,16 @@ public function zpopmax(string $key, int $value = null): RedisCluster|bool|array
412412

413413
public function zpopmin(string $key, int $value = null): RedisCluster|bool|array;
414414

415-
public function zrange(string $key, int $start, int $end, mixed $options_withscores = null): RedisCluster|array|bool;
415+
/**
416+
* @see Redis::zrange
417+
*/
418+
public function zrange(string $key, mixed $start, mixed $end, array|bool|null $options = null): RedisCluster|array|bool;
419+
420+
/**
421+
* @see Redis::zrangestore
422+
*/
423+
public function zrangestore(string $dstkey, string $srckey, int $start, int $end,
424+
array|bool|null $options = null): RedisCluster|int|false;
416425

417426
public function zrangebylex(string $key, string $min, string $max, int $offset = -1, int $count = -1): RedisCluster|array|false;
418427

0 commit comments

Comments
 (0)