You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kvrocks.apache.org by hu...@apache.org on 2023/06/15 03:13:37 UTC
[incubator-kvrocks] branch unstable updated: Fix ZRANGE command should return an empty array when count = 0 (#1492)
This is an automated email from the ASF dual-hosted git repository.
hulk pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/incubator-kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new 46e7eaf4 Fix ZRANGE command should return an empty array when count = 0 (#1492)
46e7eaf4 is described below
commit 46e7eaf428c3e4935cc73f70be3f8c9066d5cb3c
Author: clundro <in...@outlook.com>
AuthorDate: Thu Jun 15 11:13:31 2023 +0800
Fix ZRANGE command should return an empty array when count = 0 (#1492)
Currently, ZRANGE will return all matched members if the count = 0 which is not consistent
with the Redis behavior. For example:
```shell
127.0.0.1:6666> zadd zset11 1 a 2 b 3 c 4 d 5 e 6 f 7 g
(integer) 7
127.0.0.1:6666> zrange zset11 0 6 byscore limit 0 0
```
Redis will return an empty array:
```shell
127.0.0.1:6379> zadd zset11 1 a 2 b 3 c 4 d 5 e 6 f 7 g
(integer) 7
127.0.0.1:6379> zrange zset11 0 6 byscore limit 0 0
(empty array)
```
But we got all matched members in ZSET:
```shell
127.0.0.1:6666> zrange zset11 0 6 byscore limit 0 0
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
```
---
src/commands/cmd_zset.cc | 16 +++++++++++++++-
tests/gocase/unit/type/zset/zset_test.go | 29 +++++++++++++++++++++++++++++
2 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/src/commands/cmd_zset.cc b/src/commands/cmd_zset.cc
index 216288fd..6ba6f1d9 100644
--- a/src/commands/cmd_zset.cc
+++ b/src/commands/cmd_zset.cc
@@ -24,6 +24,7 @@
#include "commander.h"
#include "commands/scan_base.h"
#include "error_constants.h"
+#include "server/redis_reply.h"
#include "server/server.h"
#include "types/redis_zset.h"
@@ -454,6 +455,12 @@ class CommandZRangeStore : public Commander {
RangeScoreSpec score_spec_;
};
+/*
+ * description:
+ * syntax: `ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count]
+ * [WITHSCORES]`
+ *
+ */
class CommandZRangeGeneric : public Commander {
public:
explicit CommandZRangeGeneric(ZRangeType range_type = kZRangeAuto, ZRangeDirection direction = kZRangeDirectionAuto)
@@ -545,7 +552,6 @@ class CommandZRangeGeneric : public Commander {
Status Execute(Server *svr, Connection *conn, std::string *output) override {
redis::ZSet zset_db(svr->storage, conn->GetNamespace());
-
std::vector<MemberScore> member_scores;
rocksdb::Status s;
@@ -555,9 +561,17 @@ class CommandZRangeGeneric : public Commander {
s = zset_db.RangeByRank(key_, rank_spec_, &member_scores, nullptr);
break;
case kZRangeScore:
+ if (score_spec_.count == 0) {
+ *output = redis::MultiBulkString({});
+ return Status::OK();
+ }
s = zset_db.RangeByScore(key_, score_spec_, &member_scores, nullptr);
break;
case kZRangeLex:
+ if (lex_spec_.count == 0) {
+ *output = redis::MultiBulkString({});
+ return Status::OK();
+ }
s = zset_db.RangeByLex(key_, lex_spec_, &member_scores, nullptr);
break;
}
diff --git a/tests/gocase/unit/type/zset/zset_test.go b/tests/gocase/unit/type/zset/zset_test.go
index 872e075a..94a16b61 100644
--- a/tests/gocase/unit/type/zset/zset_test.go
+++ b/tests/gocase/unit/type/zset/zset_test.go
@@ -28,6 +28,7 @@ import (
"strconv"
"strings"
"testing"
+ "time"
"github.com/apache/incubator-kvrocks/tests/gocase/util"
"github.com/redis/go-redis/v9"
@@ -439,6 +440,33 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s
{4, "d"},
}, rdb.ZRangeWithScores(ctx, "ztmp", 0, -1).Val())
+ for i := 1; i < 10; i++ {
+ cmd := rdb.ZRangeArgs(ctx, redis.ZRangeArgs{Key: "ztmp", Count: 0, ByScore: true, Start: 0, Stop: -1, Offset: int64(i)})
+ require.NoError(t, cmd.Err())
+ require.Equal(t, []string{}, cmd.Val())
+ }
+
+ // go-redis removes the limit condition when (offset, count) == (0, 0)
+ // so we use (offset, count) = (0, -1)
+ cmd1 := rdb.Do(ctx, "zrange", "ztmp", 0, -1, "byscore", "limit", 0, 0)
+ require.NoError(t, cmd1.Err())
+ require.Equal(t, []interface{}{}, cmd1.Val())
+
+ // limit with zero count
+ for i := 0; i < 20; i++ {
+ var args [3]int64
+ for j := 0; j < 3; j++ {
+ rand.Seed(time.Now().UnixNano())
+ args[j] = rand.Int63n(20) - 10
+ }
+ if args[2] == 0 {
+ continue
+ }
+ cmd := rdb.ZRangeArgs(ctx, redis.ZRangeArgs{Key: "ztmp", Count: 0, ByScore: true, Start: args[0], Stop: args[1], Offset: args[2]})
+ require.NoError(t, cmd.Err())
+ require.Equal(t, []string{}, cmd.Val())
+ }
+
// extend zrange commands
require.Equal(t, []string{"a", "b", "c", "d"}, rdb.ZRangeArgs(ctx, redis.ZRangeArgs{Key: "ztmp", Start: 0, Stop: -1, Offset: 0, Count: -1}).Val())
require.Equal(t, []string{"d", "c", "b", "a"}, rdb.ZRangeArgs(ctx, redis.ZRangeArgs{Key: "ztmp", Start: 0, Stop: -1, Offset: 0, Count: -1, Rev: true}).Val())
@@ -454,6 +482,7 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx context.Context, encoding s
{2, "b"},
{1, "a"},
}, rdb.ZRangeArgsWithScores(ctx, redis.ZRangeArgs{Key: "ztmp", Start: 0, Stop: -1, Offset: 0, Count: -1, Rev: true}).Val())
+
})
t.Run(fmt.Sprintf("ZREVRANGE basics - %s", encoding), func(t *testing.T) {