Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/phpredis/phpredis.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormichael-grunder <michael.grunder@gmail.com>2022-10-22 22:18:31 +0300
committerMichael Grunder <michael.grunder@gmail.com>2022-10-22 22:46:01 +0300
commit71bcbcb973413ae933cf30d58254dfb02425c1ed (patch)
tree4789de334e9f5900043a1e9fe7e680cb23b93c98
parentf3a408305a3df04b6aaaede5fa7f37ddca1f8efb (diff)
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
-rw-r--r--cluster_library.c11
-rw-r--r--cluster_library.h3
-rw-r--r--library.c12
-rw-r--r--library.h1
-rw-r--r--redis.c59
-rw-r--r--redis.stub.php58
-rw-r--r--redis_arginfo.h25
-rw-r--r--redis_cluster.c53
-rw-r--r--redis_cluster.stub.php11
-rw-r--r--redis_cluster_arginfo.h14
-rw-r--r--redis_cluster_legacy_arginfo.h21
-rw-r--r--redis_commands.c288
-rw-r--r--redis_commands.h7
-rw-r--r--redis_legacy_arginfo.h22
-rw-r--r--tests/RedisTest.php33
15 files changed, 386 insertions, 232 deletions
diff --git a/cluster_library.c b/cluster_library.c
index fe574e50..90a6f95e 100644
--- a/cluster_library.c
+++ b/cluster_library.c
@@ -2115,6 +2115,17 @@ cluster_variant_resp_generic(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
cluster_free_reply(r, 1);
}
+PHP_REDIS_API void
+cluster_zrange_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c, void *ctx) {
+ cluster_cb cb;
+
+ ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
+
+ cb = ctx ? cluster_mbulk_zipdbl_resp : cluster_mbulk_resp;
+
+ cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, ctx);
+}
+
PHP_REDIS_API void cluster_variant_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx)
{
diff --git a/cluster_library.h b/cluster_library.h
index 1f18c35a..74ede7a4 100644
--- a/cluster_library.h
+++ b/cluster_library.h
@@ -437,6 +437,9 @@ PHP_REDIS_API void cluster_sub_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *
PHP_REDIS_API void cluster_unsub_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
void *ctx);
+PHP_REDIS_API void cluster_zrange_resp(INTERNAL_FUNCTION_PARAMETERS, redisCluster *c,
+ void *ctx);
+
PHP_REDIS_API void cluster_variant_resp(INTERNAL_FUNCTION_PARAMETERS,
redisCluster *c, void *ctx);
diff --git a/library.c b/library.c
index 3c8f5c4d..66d6178f 100644
--- a/library.c
+++ b/library.c
@@ -1160,6 +1160,18 @@ redis_config_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval
return cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, ctx);
}
+PHP_REDIS_API int
+redis_zrange_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
+ FailableResultCallback cb;
+
+ /* Whether or not we have WITHSCORES */
+ ZEND_ASSERT(ctx == NULL || ctx == PHPREDIS_CTX_PTR);
+
+ cb = ctx ? redis_mbulk_reply_zipped_keys_dbl : redis_sock_read_multibulk_reply;
+
+ return cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, ctx);
+}
+
PHP_REDIS_API int redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) {
char *response;
int response_len;
diff --git a/library.h b/library.h
index 036cb456..268c838b 100644
--- a/library.h
+++ b/library.h
@@ -68,6 +68,7 @@ PHP_REDIS_API int redis_string_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock
PHP_REDIS_API int redis_ping_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_info_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_config_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
+PHP_REDIS_API int redis_zrange_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API void redis_parse_info_response(char *response, zval *z_ret);
PHP_REDIS_API void redis_parse_client_list_response(char *response, zval *z_ret);
PHP_REDIS_API int redis_type_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
diff --git a/redis.c b/redis.c
index 016658f3..adfb6827 100644
--- a/redis.c
+++ b/redis.c
@@ -1906,77 +1906,38 @@ PHP_METHOD(Redis, zAdd) {
}
/* }}} */
-/* Handle ZRANGE and ZREVRANGE as they're the same except for keyword */
-static void generic_zrange_cmd(INTERNAL_FUNCTION_PARAMETERS, char *kw,
- zrange_cb fun)
-{
- char *cmd;
- int cmd_len;
- RedisSock *redis_sock;
- int withscores = 0;
-
- if ((redis_sock = redis_sock_get(getThis(), 0)) == NULL) {
- RETURN_FALSE;
- }
-
- if(fun(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, kw, &cmd,
- &cmd_len, &withscores, NULL, NULL) == FAILURE)
- {
- RETURN_FALSE;
- }
-
- REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
- if(withscores) {
- if (IS_ATOMIC(redis_sock)) {
- redis_mbulk_reply_zipped_keys_dbl(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL);
- }
- REDIS_PROCESS_RESPONSE(redis_mbulk_reply_zipped_keys_dbl);
- } else {
- if (IS_ATOMIC(redis_sock)) {
- if(redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU,
- redis_sock, NULL, NULL) < 0)
- {
- RETURN_FALSE;
- }
- }
- REDIS_PROCESS_RESPONSE(redis_sock_read_multibulk_reply);
- }
-}
-
/* {{{ proto array Redis::zRandMember(string key, array options) */
-PHP_METHOD(Redis, zRandMember)
-{
+PHP_METHOD(Redis, zRandMember) {
REDIS_PROCESS_CMD(zrandmember, redis_zrandmember_response);
}
/* }}} */
/* {{{ proto array Redis::zRange(string key,int start,int end,bool scores = 0) */
-PHP_METHOD(Redis, zRange)
-{
- generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZRANGE",
- redis_zrange_cmd);
+PHP_METHOD(Redis, zRange) {
+ REDIS_PROCESS_KW_CMD("ZRANGE", redis_zrange_cmd, redis_zrange_response);
}
/* }}} */
+PHP_METHOD(Redis, zrangestore) {
+ REDIS_PROCESS_KW_CMD("ZRANGESTORE", redis_zrange_cmd, redis_long_response);
+}
+
/* {{{ proto array Redis::zRevRange(string k, long s, long e, bool scores = 0) */
PHP_METHOD(Redis, zRevRange) {
- generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZREVRANGE",
- redis_zrange_cmd);
+ REDIS_PROCESS_KW_CMD("ZREVRANGE", redis_zrange_cmd, redis_zrange_response);
}
/* }}} */
/* {{{ proto array Redis::zRangeByScore(string k,string s,string e,array opt) */
PHP_METHOD(Redis, zRangeByScore) {
- generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZRANGEBYSCORE",
- redis_zrangebyscore_cmd);
+ REDIS_PROCESS_KW_CMD("ZRANGEBYSCORE", redis_zrange_cmd, redis_zrange_response);
}
/* }}} */
/* {{{ proto array Redis::zRevRangeByScore(string key, string start, string end,
* array options) */
PHP_METHOD(Redis, zRevRangeByScore) {
- generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZREVRANGEBYSCORE",
- redis_zrangebyscore_cmd);
+ REDIS_PROCESS_KW_CMD("ZREVRANGEBYSCORE", redis_zrange_cmd, redis_zrange_response);
}
/* }}} */
diff --git a/redis.stub.php b/redis.stub.php
index fd9ea3c2..51dd1fe3 100644
--- a/redis.stub.php
+++ b/redis.stub.php
@@ -694,12 +694,68 @@ class Redis {
public function zPopMin(string $key, int $value = null): Redis|array|false;
- public function zRange(string $key, int $start, int $end, mixed $scores = null): Redis|array|false;
+ /**
+ * Retreive a range of elements of a sorted set between a start and end point.
+ * How the command works in particular is greatly affected by the options that
+ * are passed in.
+ *
+ * @see https://https://redis.io/commands/zrange/
+ * @category zset
+ *
+ * @param string $key The sorted set in question.
+ * @param mixed $start The starting index we want to return.
+ * @param mixed $end The final index we want to return.
+ *
+ * @param array|bool|null $options This value may either be an array of options to pass to
+ * the command, or for historical purposes a boolean which
+ * controls just the 'WITHSCORES' option.
+ *
+ * @return Redis|array|false An array with matching elements or false on failure.
+ *
+ * Detailed description of options array:
+ *
+ * <code>
+ * <?php
+ * $options = [
+ * 'WITHSCORES' => true, // Return both scores and members.
+ * 'LIMIT' => [10, 10], // Start at offset 10 and return 10 elements.
+ * 'REV' // Return the elements in reverse order
+ * 'BYSCORE', // Treat `start` and `end` as scores instead
+ * 'BYLEX' // Treat `start` and `end` as lexographical values.
+ * ];
+ * ?>
+ * </code>
+ *
+ * Note: 'BYLEX' and 'BYSCORE' are mutually exclusive.
+ *
+ */
+ public function zRange(string $key, mixed $start, mixed $end, array|bool|null $options = null): Redis|array|false;
public function zRangeByLex(string $key, string $min, string $max, int $offset = -1, int $count = -1): Redis|array|false;
public function zRangeByScore(string $key, string $start, string $end, array $options = []): Redis|array|false;
+ /**
+ * This command is similar to ZRANGE except that instead of returning the values directly
+ * it will store them in a destination key provided by the user
+ *
+ * @see https://https://redis.io/commands/zrange/
+ * @see Redis::zRange
+ * @category zset
+ *
+ * @param string $dstkey The key to store the resulting element(s)
+ * @param string $srckey The source key with element(s) to retreive
+ * @param string $start The starting index to store
+ * @param string $end The ending index to store
+ * @param array|bool|null $options Our options array that controls how the command will function.
+ *
+ * @return Redis|int|false The number of elements stored in dstkey or false on failure.
+ *
+ * See Redis::zRange for a full description of the possible options.
+ */
+ public function zrangestore(string $dstkey, string $srckey, string $start, string $end,
+ array|bool|null $options = NULL): Redis|int|false;
+
public function zRandMember(string $key, array $options = null): Redis|string|array;
public function zRank(string $key, mixed $member): Redis|int|false;
diff --git a/redis_arginfo.h b/redis_arginfo.h
index 482ad347..38b11ccf 100644
--- a/redis_arginfo.h
+++ b/redis_arginfo.h
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
- * Stub hash: a27d28648f2d1a77237305083f36abc5e071f5b1 */
+ * Stub hash: 73bbd79b67c155a90acfa2b5ca1be49effdaf8ba */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "null")
@@ -1000,9 +1000,9 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRange, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
- ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
- ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
- ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, scores, IS_MIXED, 0, "null")
+ ZEND_ARG_TYPE_INFO(0, start, IS_MIXED, 0)
+ ZEND_ARG_TYPE_INFO(0, end, IS_MIXED, 0)
+ ZEND_ARG_TYPE_MASK(0, options, MAY_BE_ARRAY|MAY_BE_BOOL|MAY_BE_NULL, "null")
ZEND_END_ARG_INFO()
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
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zrangestore, 0, 4, Redis, MAY_BE_LONG|MAY_BE_FALSE)
+ ZEND_ARG_TYPE_INFO(0, dstkey, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, srckey, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, start, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, end, IS_STRING, 0)
+ ZEND_ARG_TYPE_MASK(0, options, MAY_BE_ARRAY|MAY_BE_BOOL|MAY_BE_NULL, "NULL")
+ZEND_END_ARG_INFO()
+
#define arginfo_class_Redis_zRandMember arginfo_class_Redis_hRandField
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()
#define arginfo_class_Redis_zRemRangeByScore arginfo_class_Redis_zCount
-#define arginfo_class_Redis_zRevRange arginfo_class_Redis_zRange
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_zRevRange, 0, 3, Redis, MAY_BE_ARRAY|MAY_BE_FALSE)
+ ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
+ ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, scores, IS_MIXED, 0, "null")
+ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zRevRangeByLex arginfo_class_Redis_zRangeByLex
@@ -1314,6 +1327,7 @@ ZEND_METHOD(Redis, zPopMin);
ZEND_METHOD(Redis, zRange);
ZEND_METHOD(Redis, zRangeByLex);
ZEND_METHOD(Redis, zRangeByScore);
+ZEND_METHOD(Redis, zrangestore);
ZEND_METHOD(Redis, zRandMember);
ZEND_METHOD(Redis, zRank);
ZEND_METHOD(Redis, zRem);
@@ -1559,6 +1573,7 @@ static const zend_function_entry class_Redis_methods[] = {
ZEND_ME(Redis, zRange, arginfo_class_Redis_zRange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRangeByLex, arginfo_class_Redis_zRangeByLex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRangeByScore, arginfo_class_Redis_zRangeByScore, ZEND_ACC_PUBLIC)
+ ZEND_ME(Redis, zrangestore, arginfo_class_Redis_zrangestore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRandMember, arginfo_class_Redis_zRandMember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRank, arginfo_class_Redis_zRank, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRem, arginfo_class_Redis_zRem, ZEND_ACC_PUBLIC)
diff --git a/redis_cluster.c b/redis_cluster.c
index 03e85d84..c5078521 100644
--- a/redis_cluster.c
+++ b/redis_cluster.c
@@ -1429,61 +1429,31 @@ PHP_METHOD(RedisCluster, setrange) {
}
/* }}} */
-/* Generic implementation for ZRANGE, ZREVRANGE, ZRANGEBYSCORE, ZREVRANGEBYSCORE */
-static void generic_zrange_cmd(INTERNAL_FUNCTION_PARAMETERS, char *kw,
- zrange_cb fun)
-{
- redisCluster *c = GET_CONTEXT();
- c->readonly = CLUSTER_IS_ATOMIC(c);
- cluster_cb cb;
- char *cmd; int cmd_len; short slot;
- int withscores = 0;
-
- if (fun(INTERNAL_FUNCTION_PARAM_PASSTHRU, c->flags, kw, &cmd, &cmd_len,
- &withscores, &slot, NULL) == FAILURE)
- {
- efree(cmd);
- RETURN_FALSE;
- }
-
- if (cluster_send_command(c,slot,cmd,cmd_len) < 0 || c->err != NULL) {
- efree(cmd);
- RETURN_FALSE;
- }
-
- efree(cmd);
-
- cb = withscores ? cluster_mbulk_zipdbl_resp : cluster_mbulk_resp;
- if (CLUSTER_IS_ATOMIC(c)) {
- cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, c, NULL);
- } else {
- void *ctx = NULL;
- CLUSTER_ENQUEUE_RESPONSE(c, slot, cb, ctx);
- RETURN_ZVAL(getThis(), 1, 0);
- }
-}
-
/* {{{ proto
* array RedisCluster::zrange(string k, long s, long e, bool score = 0) */
PHP_METHOD(RedisCluster, zrange) {
- generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZRANGE",
- redis_zrange_cmd);
+ CLUSTER_PROCESS_KW_CMD("ZRANGE", redis_zrange_cmd, cluster_zrange_resp, 1);
}
/* }}} */
/* {{{ proto
+ * array RedisCluster::zrange(string $dstkey, string $srckey, long s, long e, array|bool $options = false) */
+PHP_METHOD(RedisCluster, zrangestore) {
+ CLUSTER_PROCESS_KW_CMD("ZRANGESTORE", redis_zrange_cmd, cluster_long_resp, 0);
+}
+
+/* }}} */
+/* {{{ proto
* array RedisCluster::zrevrange(string k,long s,long e,bool scores = 0) */
PHP_METHOD(RedisCluster, zrevrange) {
- generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZREVRANGE",
- redis_zrange_cmd);
+ CLUSTER_PROCESS_KW_CMD("ZREVRANGE", redis_zrange_cmd, cluster_zrange_resp, 1);
}
/* }}} */
/* {{{ proto array
* RedisCluster::zrangebyscore(string k, long s, long e, array opts) */
PHP_METHOD(RedisCluster, zrangebyscore) {
- generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZRANGEBYSCORE",
- redis_zrangebyscore_cmd);
+ CLUSTER_PROCESS_KW_CMD("ZRANGEBYSCORE", redis_zrange_cmd, cluster_zrange_resp, 1);
}
/* }}} */
@@ -1516,8 +1486,7 @@ PHP_METHOD(RedisCluster, zrem) {
/* {{{ proto array
* RedisCluster::zrevrangebyscore(string k, long s, long e, array opts) */
PHP_METHOD(RedisCluster, zrevrangebyscore) {
- generic_zrange_cmd(INTERNAL_FUNCTION_PARAM_PASSTHRU, "ZREVRANGEBYSCORE",
- redis_zrangebyscore_cmd);
+ CLUSTER_PROCESS_KW_CMD("ZREVRANGEBYSCORE", redis_zrange_cmd, cluster_zrange_resp, 1);
}
/* }}} */
diff --git a/redis_cluster.stub.php b/redis_cluster.stub.php
index 598a8126..165dfd3b 100644
--- a/redis_cluster.stub.php
+++ b/redis_cluster.stub.php
@@ -412,7 +412,16 @@ class RedisCluster {
public function zpopmin(string $key, int $value = null): RedisCluster|bool|array;
- public function zrange(string $key, int $start, int $end, mixed $options_withscores = null): RedisCluster|array|bool;
+ /**
+ * @see Redis::zrange
+ */
+ public function zrange(string $key, mixed $start, mixed $end, array|bool|null $options = null): RedisCluster|array|bool;
+
+ /**
+ * @see Redis::zrangestore
+ */
+ public function zrangestore(string $dstkey, string $srckey, int $start, int $end,
+ array|bool|null $options = null): RedisCluster|int|false;
public function zrangebylex(string $key, string $min, string $max, int $offset = -1, int $count = -1): RedisCluster|array|false;
diff --git a/redis_cluster_arginfo.h b/redis_cluster_arginfo.h
index b6bde9f7..0b4619fb 100644
--- a/redis_cluster_arginfo.h
+++ b/redis_cluster_arginfo.h
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 7a2f14794870618a17273a2ed9f60d81449c82af */
+ * Stub hash: e761b2a65f9f57254e0201f9643b823e79e2a0a8 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 1)
@@ -864,9 +864,17 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zrange, 0, 3, RedisCluster, MAY_BE_ARRAY|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, start, IS_MIXED, 0)
+ ZEND_ARG_TYPE_INFO(0, end, IS_MIXED, 0)
+ ZEND_ARG_TYPE_MASK(0, options, MAY_BE_ARRAY|MAY_BE_BOOL|MAY_BE_NULL, "null")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zrangestore, 0, 4, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
+ ZEND_ARG_TYPE_INFO(0, dstkey, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, srckey, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, start, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, end, IS_LONG, 0)
- ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options_withscores, IS_MIXED, 0, "null")
+ ZEND_ARG_TYPE_MASK(0, options, MAY_BE_ARRAY|MAY_BE_BOOL|MAY_BE_NULL, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_zrangebylex, 0, 3, RedisCluster, MAY_BE_ARRAY|MAY_BE_FALSE)
@@ -1122,6 +1130,7 @@ ZEND_METHOD(RedisCluster, zlexcount);
ZEND_METHOD(RedisCluster, zpopmax);
ZEND_METHOD(RedisCluster, zpopmin);
ZEND_METHOD(RedisCluster, zrange);
+ZEND_METHOD(RedisCluster, zrangestore);
ZEND_METHOD(RedisCluster, zrangebylex);
ZEND_METHOD(RedisCluster, zrangebyscore);
ZEND_METHOD(RedisCluster, zrank);
@@ -1327,6 +1336,7 @@ static const zend_function_entry class_RedisCluster_methods[] = {
ZEND_ME(RedisCluster, zpopmax, arginfo_class_RedisCluster_zpopmax, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zpopmin, arginfo_class_RedisCluster_zpopmin, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrange, arginfo_class_RedisCluster_zrange, ZEND_ACC_PUBLIC)
+ ZEND_ME(RedisCluster, zrangestore, arginfo_class_RedisCluster_zrangestore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrangebylex, arginfo_class_RedisCluster_zrangebylex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrangebyscore, arginfo_class_RedisCluster_zrangebyscore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrank, arginfo_class_RedisCluster_zrank, ZEND_ACC_PUBLIC)
diff --git a/redis_cluster_legacy_arginfo.h b/redis_cluster_legacy_arginfo.h
index db11ebf5..cc73a262 100644
--- a/redis_cluster_legacy_arginfo.h
+++ b/redis_cluster_legacy_arginfo.h
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 7a2f14794870618a17273a2ed9f60d81449c82af */
+ * Stub hash: e761b2a65f9f57254e0201f9643b823e79e2a0a8 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1)
ZEND_ARG_INFO(0, name)
@@ -743,7 +743,15 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zrange, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
- ZEND_ARG_INFO(0, options_withscores)
+ ZEND_ARG_INFO(0, options)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zrangestore, 0, 0, 4)
+ ZEND_ARG_INFO(0, dstkey)
+ ZEND_ARG_INFO(0, srckey)
+ ZEND_ARG_INFO(0, start)
+ ZEND_ARG_INFO(0, end)
+ ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zrangebylex, 0, 0, 3)
@@ -754,12 +762,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zrangebylex, 0, 0, 3)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zrangebyscore, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
- ZEND_ARG_INFO(0, start)
- ZEND_ARG_INFO(0, end)
- ZEND_ARG_INFO(0, options)
-ZEND_END_ARG_INFO()
+#define arginfo_class_RedisCluster_zrangebyscore arginfo_class_RedisCluster_zrange
#define arginfo_class_RedisCluster_zrank arginfo_class_RedisCluster_hexists
@@ -979,6 +982,7 @@ ZEND_METHOD(RedisCluster, zlexcount);
ZEND_METHOD(RedisCluster, zpopmax);
ZEND_METHOD(RedisCluster, zpopmin);
ZEND_METHOD(RedisCluster, zrange);
+ZEND_METHOD(RedisCluster, zrangestore);
ZEND_METHOD(RedisCluster, zrangebylex);
ZEND_METHOD(RedisCluster, zrangebyscore);
ZEND_METHOD(RedisCluster, zrank);
@@ -1184,6 +1188,7 @@ static const zend_function_entry class_RedisCluster_methods[] = {
ZEND_ME(RedisCluster, zpopmax, arginfo_class_RedisCluster_zpopmax, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zpopmin, arginfo_class_RedisCluster_zpopmin, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrange, arginfo_class_RedisCluster_zrange, ZEND_ACC_PUBLIC)
+ ZEND_ME(RedisCluster, zrangestore, arginfo_class_RedisCluster_zrangestore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrangebylex, arginfo_class_RedisCluster_zrangebylex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrangebyscore, arginfo_class_RedisCluster_zrangebyscore, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, zrank, arginfo_class_RedisCluster_zrank, ZEND_ACC_PUBLIC)
diff --git a/redis_commands.c b/redis_commands.c
index a0a55151..08992c2c 100644
--- a/redis_commands.c
+++ b/redis_commands.c
@@ -72,6 +72,26 @@ typedef struct redisRestoreOptions {
zend_long freq;
} redisRestoreOptions;
+#define REDIS_ZRANGE_HAS_DST_KEY (1 << 0)
+#define REDIS_ZRANGE_HAS_WITHSCORES (1 << 1)
+#define REDIS_ZRANGE_HAS_BY_LEX_SCORE (1 << 2)
+#define REDIS_ZRANGE_HAS_REV (1 << 3)
+#define REDIS_ZRANGE_HAS_LIMIT (1 << 4)
+#define REDIS_ZRANGE_INT_RANGE (1 << 5)
+
+/* ZRANGE, ZRANGEBYSCORE, ZRANGESTORE options */
+typedef struct redisZrangeOptions {
+ zend_bool withscores;
+ zend_bool byscore;
+ zend_bool bylex;
+ zend_bool rev;
+ struct {
+ zend_bool enabled;
+ zend_long offset;
+ zend_long count;
+ } limit;
+} redisZrangeOptions;
+
/* Local passthrough macro for command construction. Given that these methods
* are generic (so they work whether the caller is Redis or RedisCluster) we
* will always have redis_sock, slot*, and */
@@ -612,119 +632,184 @@ int redis_fmt_scan_cmd(char **cmd, REDIS_SCAN_TYPE type, char *key, int key_len,
return cmdstr.len;
}
-/* ZRANGE/ZREVRANGE */
-int redis_zrange_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
- char *kw, char **cmd, int *cmd_len, int *withscores,
- short *slot, void **ctx)
-{
- char *key;
- size_t key_len;
- zend_long start, end;
- zend_string *zkey;
- zval *z_ws = NULL, *z_ele;
+void redis_get_zrange_options(redisZrangeOptions *dst, zval *src, int flags) {
+ zval *zv, *zoff, *zcnt;
+ zend_string *key;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll|z!", &key, &key_len,
- &start, &end, &z_ws) == FAILURE)
- {
- return FAILURE;
+ ZEND_ASSERT(dst != NULL);
+
+ memset(dst, 0, sizeof(*dst));
+
+ if (src == NULL)
+ return;
+
+ if (Z_TYPE_P(src) != IS_ARRAY) {
+ if (Z_TYPE_P(src) == IS_TRUE && (flags & REDIS_ZRANGE_HAS_WITHSCORES))
+ dst->withscores = 1;
+ return;
}
- // Clear withscores arg
- *withscores = 0;
+ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(src), key, zv) {
+ ZVAL_DEREF(zv);
- /* Accept ['withscores' => true], or the legacy `true` value */
- if (z_ws) {
- if (Z_TYPE_P(z_ws) == IS_ARRAY) {
- ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(z_ws), zkey, z_ele) {
- if (zkey != NULL) {
- ZVAL_DEREF(z_ele);
- if (zend_string_equals_literal_ci(zkey, "withscores")) {
- *withscores = zval_is_true(z_ele);
- break;
- }
+ if (key) {
+ if ((flags & REDIS_ZRANGE_HAS_WITHSCORES) && zend_string_equals_literal_ci(key, "WITHSCORES"))
+ dst->withscores = zval_is_true(zv);
+ else if ((flags & REDIS_ZRANGE_HAS_LIMIT) && zend_string_equals_literal_ci(key, "LIMIT") &&
+ Z_TYPE_P(zv) == IS_ARRAY)
+ {
+ if ((zoff = zend_hash_index_find(Z_ARRVAL_P(zv), 0)) != NULL &&
+ (zcnt = zend_hash_index_find(Z_ARRVAL_P(zv), 1)) != NULL)
+ {
+ dst->limit.enabled = 1;
+ dst->limit.offset = zval_get_long(zoff);
+ dst->limit.count = zval_get_long(zcnt);
+ } else {
+ php_error_docref(NULL, E_WARNING, "LIMIT offset and count must be an array with twe elements");
}
- } ZEND_HASH_FOREACH_END();
- } else if (Z_TYPE_P(z_ws) == IS_TRUE) {
- *withscores = Z_TYPE_P(z_ws) == IS_TRUE;
+ }
+ } else if (Z_TYPE_P(zv) == IS_STRING) {
+ key = Z_STR_P(zv);
+
+ if ((flags & REDIS_ZRANGE_HAS_BY_LEX_SCORE) && zend_string_equals_literal_ci(key, "BYSCORE"))
+ dst->byscore = 1, dst->bylex = 0;
+ else if ((flags & REDIS_ZRANGE_HAS_BY_LEX_SCORE) && zend_string_equals_literal_ci(key, "BYLEX"))
+ dst->bylex = 1, dst->byscore = 0;
+ else if ((flags & REDIS_ZRANGE_HAS_REV) && zend_string_equals_literal_ci(key, "REV"))
+ dst->rev = 1;
+ else if ((flags & REDIS_ZRANGE_HAS_WITHSCORES && zend_string_equals_literal_ci(key, "WITHSCORES")))
+ dst->withscores = 1;
}
- }
+ } ZEND_HASH_FOREACH_END();
+}
- if (*withscores) {
- *cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "kdds", key, key_len, start, end,
- "WITHSCORES", sizeof("WITHSCORES") - 1);
- } else {
- *cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "kdd", key, key_len, start, end);
+// + ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES]
+// + ZRANGESTORE dst src min max [BYSCORE | BYLEX] [REV] [LIMIT offset count]
+// + ZREVRANGE key start stop [WITHSCORES]
+// + ZRANGEBYSCORE key min max [LIMIT offset count] [WITHSCORES]
+// + ZREVRANGEBYSCORE key max min [LIMIT offset count] [WITHSCORES]
+// - ZRANGEBYLEX key min max [LIMIT offset count]
+// - ZREVRANGEBYLEX key max min [LIMIT offset count]
+static int redis_get_zrange_cmd_flags(const char *kw) {
+ size_t len = strlen(kw);
+
+ if (REDIS_STRICMP_STATIC(kw, len, "ZRANGESTORE")) {
+ return REDIS_ZRANGE_HAS_DST_KEY |
+ REDIS_ZRANGE_HAS_WITHSCORES |
+ REDIS_ZRANGE_HAS_BY_LEX_SCORE |
+ REDIS_ZRANGE_HAS_REV |
+ REDIS_ZRANGE_HAS_LIMIT;
+ } else if (REDIS_STRICMP_STATIC(kw, len, "ZRANGE")) {
+ return REDIS_ZRANGE_HAS_WITHSCORES |
+ REDIS_ZRANGE_HAS_BY_LEX_SCORE |
+ REDIS_ZRANGE_HAS_REV |
+ REDIS_ZRANGE_HAS_LIMIT;
+ } else if (REDIS_STRICMP_STATIC(kw, len, "ZREVRANGE")) {
+ return REDIS_ZRANGE_HAS_WITHSCORES |
+ REDIS_ZRANGE_INT_RANGE;
+ } else if (REDIS_STRICMP_STATIC(kw, len, "ZRANGEBYSCORE") ||
+ REDIS_STRICMP_STATIC(kw, len, "ZREVRANGEBYSCORE"))
+ {
+ return REDIS_ZRANGE_HAS_LIMIT |
+ REDIS_ZRANGE_HAS_WITHSCORES;
+ } else if (REDIS_STRICMP_STATIC(kw, len, "ZRANGEBYLEX") ||
+ REDIS_STRICMP_STATIC(kw, len, "ZREVRANGEBYLEX"))
+ {
+ return REDIS_ZRANGE_HAS_LIMIT;
}
- return SUCCESS;
+ /* Reaching this line means a compile-time error */
+ ZEND_ASSERT(0);
}
-int redis_zrangebyscore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
- char *kw, char **cmd, int *cmd_len, int *withscores,
- short *slot, void **ctx)
+/* Validate ZLEX* min/max argument strings */
+#define validate_zlex_arg_zstr(zs_) validate_zlex_arg(ZSTR_VAL((zs_)), ZSTR_LEN((zs_)))
+static int validate_zlex_arg(const char *arg, size_t len) {
+ return (len > 1 && (*arg == '[' || *arg == '(')) ||
+ (len == 1 && (*arg == '+' || *arg == '-'));
+}
+
+int redis_zrange_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+ char *kw, char **cmd, int *cmd_len, short *slot,
+ void **ctx)
{
- char *key, *start, *end;
- int has_limit = 0;
- long offset, count;
- size_t key_len, start_len, end_len;
- zval *z_opt=NULL, *z_ele;
- zend_string *zkey;
- HashTable *ht_opt;
+ zend_string *dst = NULL, *src = NULL, *sstart = NULL, *send = NULL;
+ struct redisZrangeOptions opt;
+ zend_long start = 0, end = 0;
+ smart_string cmdstr = {0};
+ zval *zoptions = NULL;
+ int min_argc, flags;
+ short slot2;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|a", &key, &key_len,
- &start, &start_len, &end, &end_len, &z_opt)
- ==FAILURE)
- {
- return FAILURE;
+ flags = redis_get_zrange_cmd_flags(kw);
+
+ min_argc = 3 + (flags & REDIS_ZRANGE_HAS_DST_KEY);
+ ZEND_PARSE_PARAMETERS_START(min_argc, min_argc + 1)
+ if (flags & REDIS_ZRANGE_HAS_DST_KEY) {
+ Z_PARAM_STR(dst)
+ }
+ Z_PARAM_STR(src)
+ if (flags & REDIS_ZRANGE_INT_RANGE) {
+ Z_PARAM_LONG(start)
+ Z_PARAM_LONG(end)
+ } else {
+ Z_PARAM_STR(sstart)
+ Z_PARAM_STR(send)
+ }
+ Z_PARAM_OPTIONAL
+ Z_PARAM_ZVAL_OR_NULL(zoptions)
+ ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
+
+ redis_get_zrange_options(&opt, zoptions, flags);
+
+ if (opt.bylex) {
+ ZEND_ASSERT(!(flags & REDIS_ZRANGE_INT_RANGE));
+ if (!validate_zlex_arg_zstr(sstart) || !validate_zlex_arg_zstr(send)) {
+ php_error_docref(NULL, E_WARNING, "Legographical args must start with '[' or '(' or be '+' or '-'");
+ return FAILURE;
+ }
}
- // Check for an options array
- if (z_opt && Z_TYPE_P(z_opt) == IS_ARRAY) {
- ht_opt = Z_ARRVAL_P(z_opt);
- ZEND_HASH_FOREACH_STR_KEY_VAL(ht_opt, zkey, z_ele) {
- /* All options require a string key type */
- if (!zkey) continue;
- ZVAL_DEREF(z_ele);
- /* Check for withscores and limit */
- if (zend_string_equals_literal_ci(zkey, "withscores")) {
- *withscores = zval_is_true(z_ele);
- } else if (zend_string_equals_literal_ci(zkey, "limit") && Z_TYPE_P(z_ele) == IS_ARRAY) {
- HashTable *htlimit = Z_ARRVAL_P(z_ele);
- zval *zoff, *zcnt;
-
- /* We need two arguments (offset and count) */
- if ((zoff = zend_hash_index_find(htlimit, 0)) != NULL &&
- (zcnt = zend_hash_index_find(htlimit, 1)) != NULL
- ) {
- /* Set our limit if we can get valid longs from both args */
- offset = zval_get_long(zoff);
- count = zval_get_long(zcnt);
- has_limit = 1;
- }
- }
- } ZEND_HASH_FOREACH_END();
+ redis_cmd_init_sstr(&cmdstr, min_argc + !!opt.bylex + !!opt.byscore +
+ !!opt.rev + !!opt.withscores +
+ (opt.limit.enabled ? 3 : 0), kw, strlen(kw));
+
+ if (flags & REDIS_ZRANGE_HAS_DST_KEY)
+ redis_cmd_append_sstr_key_zstr(&cmdstr, dst, redis_sock, slot);
+ redis_cmd_append_sstr_key_zstr(&cmdstr, src, redis_sock, &slot2);
+
+ /* Protect the user from crossslot errors */
+ if ((flags & REDIS_ZRANGE_HAS_DST_KEY) && slot && *slot != slot2) {
+ php_error_docref(NULL, E_WARNING, "destination and source keys must map to the same slot");
+ efree(cmdstr.c);
+ return FAILURE;
}
- // Construct our command
- if (*withscores) {
- if (has_limit) {
- *cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "ksssdds", key, key_len,
- start, start_len, end, end_len, "LIMIT", 5, offset, count,
- "WITHSCORES", 10);
- } else {
- *cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "ksss", key, key_len, start,
- start_len, end, end_len, "WITHSCORES", 10);
- }
+ if (flags & REDIS_ZRANGE_INT_RANGE) {
+ redis_cmd_append_sstr_long(&cmdstr, start);
+ redis_cmd_append_sstr_long(&cmdstr, end);
} else {
- if (has_limit) {
- *cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "ksssdd", key, key_len, start,
- start_len, end, end_len, "LIMIT", 5, offset, count);
- } else {
- *cmd_len = REDIS_CMD_SPPRINTF(cmd, kw, "kss", key, key_len, start,
- start_len, end, end_len);
- }
+ redis_cmd_append_sstr_zstr(&cmdstr, sstart);
+ redis_cmd_append_sstr_zstr(&cmdstr, send);
+ }
+
+ REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.byscore, "BYSCORE");
+ REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.bylex, "BYLEX");
+ REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.rev, "REV");
+
+ if (opt.limit.enabled) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "LIMIT");
+ redis_cmd_append_sstr_long(&cmdstr, opt.limit.offset);
+ redis_cmd_append_sstr_long(&cmdstr, opt.limit.count);
}
+ REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.withscores, "WITHSCORES");
+
+ if (slot) *slot = slot2;
+ *ctx = opt.withscores ? PHPREDIS_CTX_PTR : NULL;
+ *cmd = cmdstr.c;
+ *cmd_len = cmdstr.len;
+
return SUCCESS;
}
@@ -1414,14 +1499,9 @@ int redis_zrangebylex_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
}
/* min and max must start with '(' or '[', or be either '-' or '+' */
- if (min_len < 1 || max_len < 1 ||
- (min[0] != '(' && min[0] != '[' &&
- (min[0] != '-' || min_len > 1) && (min[0] != '+' || min_len > 1)) ||
- (max[0] != '(' && max[0] != '[' &&
- (max[0] != '-' || max_len > 1) && (max[0] != '+' || max_len > 1)))
- {
- php_error_docref(0, E_WARNING,
- "min and max arguments must start with '[' or '('");
+ if (!validate_zlex_arg(min, min_len) || !validate_zlex_arg(max, max_len)) {
+ php_error_docref(NULL, E_WARNING,
+ "Min/Max args can be '-' or '+', or start with '[' or '('");
return FAILURE;
}
@@ -1437,12 +1517,6 @@ int redis_zrangebylex_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
return SUCCESS;
}
-/* Validate ZLEX* min/max argument strings */
-static int validate_zlex_arg(const char *arg, size_t len) {
- return (len > 1 && (*arg == '[' || *arg == '(')) ||
- (len == 1 && (*arg == '+' || *arg == '-'));
-}
-
/* ZLEXCOUNT/ZREMRANGEBYLEX */
int redis_gen_zlex_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot,
diff --git a/redis_commands.h b/redis_commands.h
index 50512a3d..4d7a13e0 100644
--- a/redis_commands.h
+++ b/redis_commands.h
@@ -103,12 +103,7 @@ typedef int (*zrange_cb)(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *,char**,int*,int*,short*,void**);
int redis_zrange_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
- char *kw, char **cmd, int *cmd_len, int *withscores, short *slot,
- void **ctx);
-
-int redis_zrangebyscore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
- char *kw, char **cmd, int *cmd_len, int *withscores, short *slot,
- void **ctx);
+ char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_config_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
diff --git a/redis_legacy_arginfo.h b/redis_legacy_arginfo.h
index 2bdf5e12..b5b39586 100644
--- a/redis_legacy_arginfo.h
+++ b/redis_legacy_arginfo.h
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
- * Stub hash: a27d28648f2d1a77237305083f36abc5e071f5b1 */
+ * Stub hash: 73bbd79b67c155a90acfa2b5ca1be49effdaf8ba */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0)
ZEND_ARG_INFO(0, options)
@@ -858,7 +858,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zRange, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
- ZEND_ARG_INFO(0, scores)
+ ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zRangeByLex, 0, 0, 3)
@@ -869,8 +869,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zRangeByLex, 0, 0, 3)
ZEND_ARG_INFO(0, count)
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zRangeByScore, 0, 0, 3)
- ZEND_ARG_INFO(0, key)
+#define arginfo_class_Redis_zRangeByScore arginfo_class_Redis_zRange
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zrangestore, 0, 0, 4)
+ ZEND_ARG_INFO(0, dstkey)
+ ZEND_ARG_INFO(0, srckey)
ZEND_ARG_INFO(0, start)
ZEND_ARG_INFO(0, end)
ZEND_ARG_INFO(0, options)
@@ -888,11 +891,16 @@ ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zRemRangeByScore arginfo_class_Redis_getRange
-#define arginfo_class_Redis_zRevRange arginfo_class_Redis_zRange
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zRevRange, 0, 0, 3)
+ ZEND_ARG_INFO(0, key)
+ ZEND_ARG_INFO(0, start)
+ ZEND_ARG_INFO(0, end)
+ ZEND_ARG_INFO(0, scores)
+ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zRevRangeByLex arginfo_class_Redis_zRangeByLex
-#define arginfo_class_Redis_zRevRangeByScore arginfo_class_Redis_zRangeByScore
+#define arginfo_class_Redis_zRevRangeByScore arginfo_class_Redis_zRange
#define arginfo_class_Redis_zRevRank arginfo_class_Redis_hExists
@@ -1151,6 +1159,7 @@ ZEND_METHOD(Redis, zPopMin);
ZEND_METHOD(Redis, zRange);
ZEND_METHOD(Redis, zRangeByLex);
ZEND_METHOD(Redis, zRangeByScore);
+ZEND_METHOD(Redis, zrangestore);
ZEND_METHOD(Redis, zRandMember);
ZEND_METHOD(Redis, zRank);
ZEND_METHOD(Redis, zRem);
@@ -1396,6 +1405,7 @@ static const zend_function_entry class_Redis_methods[] = {
ZEND_ME(Redis, zRange, arginfo_class_Redis_zRange, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRangeByLex, arginfo_class_Redis_zRangeByLex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRangeByScore, arginfo_class_Redis_zRangeByScore, ZEND_ACC_PUBLIC)
+ ZEND_ME(Redis, zrangestore, arginfo_class_Redis_zrangestore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRandMember, arginfo_class_Redis_zRandMember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRank, arginfo_class_Redis_zRank, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, zRem, arginfo_class_Redis_zRem, ZEND_ACC_PUBLIC)
diff --git a/tests/RedisTest.php b/tests/RedisTest.php
index 52b86330..149bbb84 100644
--- a/tests/RedisTest.php
+++ b/tests/RedisTest.php
@@ -2566,6 +2566,9 @@ class Redis_Test extends TestSuite
$this->assertTrue(['val1', 'val2'] === $this->redis->zRangeByScore('key', 0, 3, ['limit' => [1, 2]]));
$this->assertTrue(['val0', 'val1'] === $this->redis->zRangeByScore('key', 0, 1, ['limit' => [0, 100]]));
+ if ($this->minVersionCheck('6.2.0'))
+ $this->assertEquals(['val0', 'val1'], $this->redis->zrange('key', 0, 1, ['byscore', 'limit' => [0, 100]]));
+
// limits as references
$limit = [0, 100];
foreach ($limit as &$val) {}
@@ -2576,6 +2579,17 @@ class Redis_Test extends TestSuite
$this->assertTrue(['val2', 'val1'] === $this->redis->zRevRangeByScore('key', 3, 0, ['limit' => [1, 2]]));
$this->assertTrue(['val1', 'val0'] === $this->redis->zRevRangeByScore('key', 1, 0, ['limit' => [0, 100]]));
+ if ($this->minVersionCheck('6.2.0')) {
+ $this->assertEquals(['val1', 'val0'], $this->redis->zrange('key', 1, 0, ['byscore', 'rev', 'limit' => [0, 100]]));
+ $this->assertEquals(2, $this->redis->zrangestore('dst{key}', 'key', 1, 0,
+ ['byscore', 'rev', 'limit' => [0, 100]]));
+ $this->assertEquals(['val0', 'val1'], $this->redis->zRange('dst{key}', 0, -1));
+
+ $this->assertEquals(1, $this->redis->zrangestore('dst{key}', 'key', 1, 0,
+ ['byscore', 'rev', 'limit' => [0, 1]]));
+ $this->assertEquals(['val1'], $this->redis->zrange('dst{key}', 0, -1));
+ }
+
$this->assertTrue(4 === $this->redis->zCard('key'));
$this->assertTrue(1.0 === $this->redis->zScore('key', 'val1'));
$this->assertFalse($this->redis->zScore('key', 'val'));
@@ -2597,7 +2611,6 @@ class Redis_Test extends TestSuite
$this->assertTrue(1 == $this->redis->zCount('zset', '(1', 2));
$this->assertTrue(0 == $this->redis->zCount('zset', '(1', '(2'));
-
// zincrby
$this->redis->del('key');
$this->assertTrue(1.0 === $this->redis->zIncrBy('key', 1, 'val1'));
@@ -2817,12 +2830,22 @@ class Redis_Test extends TestSuite
$this->redis->zAdd('key', 0, $c);
}
- $this->assertEquals($this->redis->zRangeByLex('key', '-', '[c'), ['a', 'b', 'c']);
- $this->assertEquals($this->redis->zRangeByLex('key', '(e', '+'), ['f', 'g']);
+ $this->assertEquals(['a', 'b', 'c'], $this->redis->zRangeByLex('key', '-', '[c'));
+ $this->assertEquals(['f', 'g'], $this->redis->zRangeByLex('key', '(e', '+'));
+
// with limit offset
- $this->assertEquals($this->redis->zRangeByLex('key', '-', '[c', 1, 2), ['b', 'c'] );
- $this->assertEquals($this->redis->zRangeByLex('key', '-', '(c', 1, 2), ['b']);
+ $this->assertEquals(['b', 'c'], $this->redis->zRangeByLex('key', '-', '[c', 1, 2) );
+ $this->assertEquals(['b'], $this->redis->zRangeByLex('key', '-', '(c', 1, 2));
+
+ /* Test getting the same functionality via ZRANGE and options */
+ if ($this->minVersionCheck("6.2.0")) {
+ $this->assertEquals(['a','b','c'], $this->redis->zRange('key', '-', '[c', ['BYLEX']));
+ $this->assertEquals(['b', 'c'], $this->redis->zRange('key', '-', '[c', ['BYLEX', 'LIMIT' => [1, 2]]));
+ $this->assertEquals(['b'], $this->redis->zRange('key', '-', '(c', ['BYLEX', 'LIMIT' => [1, 2]]));
+
+ $this->assertEquals(['b', 'a'], $this->redis->zRange('key', '[c', '-', ['BYLEX', 'REV', 'LIMIT' => [1, 2]]));
+ }
}
public function testZLexCount() {