Commit 797c9ffb authored by Pieter Noordhuis's avatar Pieter Noordhuis
Browse files

backport of patches that fix the behavior of LRANGE, LTRIM, ZRANGE, ZREVRANGE

and ZREMRANGEBYSCORE when an out of range negative end index is provided
original commits: 184d74, 4774a5, f483ce
parent 75d675d9
...@@ -4887,9 +4887,9 @@ static void lrangeCommand(redisClient *c) { ...@@ -4887,9 +4887,9 @@ static void lrangeCommand(redisClient *c) {
if (start < 0) start = llen+start; if (start < 0) start = llen+start;
if (end < 0) end = llen+end; if (end < 0) end = llen+end;
if (start < 0) start = 0; if (start < 0) start = 0;
if (end < 0) end = 0;
/* indexes sanity checks */ /* Invariant: start >= 0, so this test will be true when end < 0.
* The range is empty when start > end or start >= length. */
if (start > end || start >= llen) { if (start > end || start >= llen) {
/* Out of range start or start > end result in empty list */ /* Out of range start or start > end result in empty list */
addReply(c,shared.emptymultibulk); addReply(c,shared.emptymultibulk);
...@@ -4926,9 +4926,9 @@ static void ltrimCommand(redisClient *c) { ...@@ -4926,9 +4926,9 @@ static void ltrimCommand(redisClient *c) {
if (start < 0) start = llen+start; if (start < 0) start = llen+start;
if (end < 0) end = llen+end; if (end < 0) end = llen+end;
if (start < 0) start = 0; if (start < 0) start = 0;
if (end < 0) end = 0;
/* indexes sanity checks */ /* Invariant: start >= 0, so this test will be true when end < 0.
* The range is empty when start > end or start >= length. */
if (start > end || start >= llen) { if (start > end || start >= llen) {
/* Out of range start or start > end result in empty list */ /* Out of range start or start > end result in empty list */
ltrim = llen; ltrim = llen;
...@@ -5893,9 +5893,9 @@ static void zremrangebyrankCommand(redisClient *c) { ...@@ -5893,9 +5893,9 @@ static void zremrangebyrankCommand(redisClient *c) {
if (start < 0) start = llen+start; if (start < 0) start = llen+start;
if (end < 0) end = llen+end; if (end < 0) end = llen+end;
if (start < 0) start = 0; if (start < 0) start = 0;
if (end < 0) end = 0;
/* indexes sanity checks */ /* Invariant: start >= 0, so this test will be true when end < 0.
* The range is empty when start > end or start >= length. */
if (start > end || start >= llen) { if (start > end || start >= llen) {
addReply(c,shared.czero); addReply(c,shared.czero);
return; return;
...@@ -6143,11 +6143,10 @@ static void zrangeGenericCommand(redisClient *c, int reverse) { ...@@ -6143,11 +6143,10 @@ static void zrangeGenericCommand(redisClient *c, int reverse) {
if (start < 0) start = llen+start; if (start < 0) start = llen+start;
if (end < 0) end = llen+end; if (end < 0) end = llen+end;
if (start < 0) start = 0; if (start < 0) start = 0;
if (end < 0) end = 0;
/* indexes sanity checks */ /* Invariant: start >= 0, so this test will be true when end < 0.
* The range is empty when start > end or start >= length. */
if (start > end || start >= llen) { if (start > end || start >= llen) {
/* Out of range start or start > end result in empty list */
addReply(c,shared.emptymultibulk); addReply(c,shared.emptymultibulk);
return; return;
} }
......
...@@ -210,6 +210,10 @@ start_server {tags {"list"}} { ...@@ -210,6 +210,10 @@ start_server {tags {"list"}} {
r lrange mylist -1000 1000 r lrange mylist -1000 1000
} {0 1 2 3 4 5 6 7 8 9} } {0 1 2 3 4 5 6 7 8 9}
test {LRANGE out of range negative end index} {
list [r lrange mylist 0 -10] [r lrange mylist 0 -11]
} {0 {}}
test {LRANGE against non existing key} { test {LRANGE against non existing key} {
r lrange nosuchkey 0 1 r lrange nosuchkey 0 1
} {} } {}
...@@ -223,6 +227,11 @@ start_server {tags {"list"}} { ...@@ -223,6 +227,11 @@ start_server {tags {"list"}} {
r lrange mylist 0 -1 r lrange mylist 0 -1
} {99 98 97 96 95} } {99 98 97 96 95}
test {LTRIM with out of range negative end index} {
r ltrim mylist 0 -6
r llen mylist
} {0}
test {LTRIM stress testing} { test {LTRIM stress testing} {
set mylist {} set mylist {}
set err {} set err {}
......
start_server {tags {"zset"}} { start_server {tags {"zset"}} {
proc create_zset {key items} {
r del $key
foreach {score entry} $items {
r zadd $key $score $entry
}
}
test {ZSET basic ZADD and score update} { test {ZSET basic ZADD and score update} {
r zadd ztmp 10 x r zadd ztmp 10 x
r zadd ztmp 20 y r zadd ztmp 20 y
...@@ -17,6 +24,66 @@ start_server {tags {"zset"}} { ...@@ -17,6 +24,66 @@ start_server {tags {"zset"}} {
r zcard ztmp-blabla r zcard ztmp-blabla
} {0} } {0}
test "ZRANGE basics" {
r del ztmp
r zadd ztmp 1 a
r zadd ztmp 2 b
r zadd ztmp 3 c
r zadd ztmp 4 d
assert_equal {a b c d} [r zrange ztmp 0 -1]
assert_equal {a b c} [r zrange ztmp 0 -2]
assert_equal {b c d} [r zrange ztmp 1 -1]
assert_equal {b c} [r zrange ztmp 1 -2]
assert_equal {c d} [r zrange ztmp -2 -1]
assert_equal {c} [r zrange ztmp -2 -2]
# out of range start index
assert_equal {a b c} [r zrange ztmp -5 2]
assert_equal {a b} [r zrange ztmp -5 1]
assert_equal {} [r zrange ztmp 5 -1]
assert_equal {} [r zrange ztmp 5 -2]
# out of range end index
assert_equal {a b c d} [r zrange ztmp 0 5]
assert_equal {b c d} [r zrange ztmp 1 5]
assert_equal {} [r zrange ztmp 0 -5]
assert_equal {} [r zrange ztmp 1 -5]
# withscores
assert_equal {a 1 b 2 c 3 d 4} [r zrange ztmp 0 -1 withscores]
}
test "ZREVRANGE basics" {
r del ztmp
r zadd ztmp 1 a
r zadd ztmp 2 b
r zadd ztmp 3 c
r zadd ztmp 4 d
assert_equal {d c b a} [r zrevrange ztmp 0 -1]
assert_equal {d c b} [r zrevrange ztmp 0 -2]
assert_equal {c b a} [r zrevrange ztmp 1 -1]
assert_equal {c b} [r zrevrange ztmp 1 -2]
assert_equal {b a} [r zrevrange ztmp -2 -1]
assert_equal {b} [r zrevrange ztmp -2 -2]
# out of range start index
assert_equal {d c b} [r zrevrange ztmp -5 2]
assert_equal {d c} [r zrevrange ztmp -5 1]
assert_equal {} [r zrevrange ztmp 5 -1]
assert_equal {} [r zrevrange ztmp 5 -2]
# out of range end index
assert_equal {d c b a} [r zrevrange ztmp 0 5]
assert_equal {c b a} [r zrevrange ztmp 1 5]
assert_equal {} [r zrevrange ztmp 0 -5]
assert_equal {} [r zrevrange ztmp 1 -5]
# withscores
assert_equal {d 4 c 3 b 2 a 1} [r zrevrange ztmp 0 -1 withscores]
}
test {ZRANK basics} { test {ZRANK basics} {
r zadd zranktmp 10 x r zadd zranktmp 10 x
r zadd zranktmp 20 y r zadd zranktmp 20 y
...@@ -69,15 +136,6 @@ start_server {tags {"zset"}} { ...@@ -69,15 +136,6 @@ start_server {tags {"zset"}} {
set _ $err set _ $err
} {} } {}
test {ZRANGE and ZREVRANGE basics} {
list [r zrange ztmp 0 -1] [r zrevrange ztmp 0 -1] \
[r zrange ztmp 1 -1] [r zrevrange ztmp 1 -1]
} {{y x z} {z x y} {x z} {x y}}
test {ZRANGE WITHSCORES} {
r zrange ztmp 0 -1 withscores
} {y 1 x 10 z 30}
test {ZSETs stress tester - sorting is working well?} { test {ZSETs stress tester - sorting is working well?} {
set delta 0 set delta 0
for {set test 0} {$test < 2} {incr test} { for {set test 0} {$test < 2} {incr test} {
...@@ -288,15 +346,32 @@ start_server {tags {"zset"}} { ...@@ -288,15 +346,32 @@ start_server {tags {"zset"}} {
list [r zremrangebyscore zset -inf +inf] [r zrange zset 0 -1] list [r zremrangebyscore zset -inf +inf] [r zrange zset 0 -1]
} {5 {}} } {5 {}}
test {ZREMRANGEBYRANK basics} { test "ZREMRANGEBYRANK basics" {
r del zset proc remrangebyrank {min max} {
r zadd zset 1 a create_zset zset {1 a 2 b 3 c 4 d 5 e}
r zadd zset 2 b r zremrangebyrank zset $min $max
r zadd zset 3 c }
r zadd zset 4 d
r zadd zset 5 e # inner range
list [r zremrangebyrank zset 1 3] [r zrange zset 0 -1] assert_equal 3 [remrangebyrank 1 3]
} {3 {a e}} assert_equal {a e} [r zrange zset 0 -1]
# start underflow
assert_equal 1 [remrangebyrank -10 0]
assert_equal {b c d e} [r zrange zset 0 -1]
# start overflow
assert_equal 0 [remrangebyrank 10 -1]
assert_equal {a b c d e} [r zrange zset 0 -1]
# end underflow
assert_equal 0 [remrangebyrank 0 -10]
assert_equal {a b c d e} [r zrange zset 0 -1]
# end overflow
assert_equal 5 [remrangebyrank 0 10]
assert_equal {} [r zrange zset 0 -1]
}
test {ZUNIONSTORE against non-existing key doesn't set destination} { test {ZUNIONSTORE against non-existing key doesn't set destination} {
r del zseta r del zseta
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment