Skip to content

Commit

Permalink
Fix ZRANGE command should return an empty array when count = 0 (#1492)
Browse files Browse the repository at this point in the history
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"
```
  • Loading branch information
infdahai authored Jun 15, 2023
1 parent 940654a commit 46e7eaf
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
16 changes: 15 additions & 1 deletion src/commands/cmd_zset.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down
29 changes: 29 additions & 0 deletions tests/gocase/unit/type/zset/zset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"strconv"
"strings"
"testing"
"time"

"github.com/apache/incubator-kvrocks/tests/gocase/util"
"github.com/redis/go-redis/v9"
Expand Down Expand Up @@ -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())
Expand All @@ -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) {
Expand Down

0 comments on commit 46e7eaf

Please sign in to comment.