Commit ef11bccc authored by Pieter Noordhuis's avatar Pieter Noordhuis
Browse files

Refactor and rename SUBSTR to GETRANGE

SUBSTR is renamed to GETRANGE to have better consistency between command
names (with SETRANGE as its dual). GETRANGE is still aliased as SUBSTR.
parent 9f9e1cea
...@@ -74,13 +74,14 @@ struct redisCommand readonlyCommandTable[] = { ...@@ -74,13 +74,14 @@ struct redisCommand readonlyCommandTable[] = {
{"setnx",setnxCommand,3,REDIS_CMD_DENYOOM,NULL,0,0,0}, {"setnx",setnxCommand,3,REDIS_CMD_DENYOOM,NULL,0,0,0},
{"setex",setexCommand,4,REDIS_CMD_DENYOOM,NULL,0,0,0}, {"setex",setexCommand,4,REDIS_CMD_DENYOOM,NULL,0,0,0},
{"append",appendCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1}, {"append",appendCommand,3,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"substr",substrCommand,4,0,NULL,1,1,1},
{"strlen",strlenCommand,2,0,NULL,1,1,1}, {"strlen",strlenCommand,2,0,NULL,1,1,1},
{"del",delCommand,-2,0,NULL,0,0,0}, {"del",delCommand,-2,0,NULL,0,0,0},
{"exists",existsCommand,2,0,NULL,1,1,1}, {"exists",existsCommand,2,0,NULL,1,1,1},
{"setbit",setbitCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1}, {"setbit",setbitCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"getbit",getbitCommand,3,0,NULL,1,1,1}, {"getbit",getbitCommand,3,0,NULL,1,1,1},
{"setrange",setrangeCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1}, {"setrange",setrangeCommand,4,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"getrange",getrangeCommand,4,0,NULL,1,1,1},
{"substr",getrangeCommand,4,0,NULL,1,1,1},
{"incr",incrCommand,2,REDIS_CMD_DENYOOM,NULL,1,1,1}, {"incr",incrCommand,2,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"decr",decrCommand,2,REDIS_CMD_DENYOOM,NULL,1,1,1}, {"decr",decrCommand,2,REDIS_CMD_DENYOOM,NULL,1,1,1},
{"mget",mgetCommand,-2,0,NULL,1,-1,1}, {"mget",mgetCommand,-2,0,NULL,1,-1,1},
......
...@@ -890,6 +890,7 @@ void existsCommand(redisClient *c); ...@@ -890,6 +890,7 @@ void existsCommand(redisClient *c);
void setbitCommand(redisClient *c); void setbitCommand(redisClient *c);
void getbitCommand(redisClient *c); void getbitCommand(redisClient *c);
void setrangeCommand(redisClient *c); void setrangeCommand(redisClient *c);
void getrangeCommand(redisClient *c);
void incrCommand(redisClient *c); void incrCommand(redisClient *c);
void decrCommand(redisClient *c); void decrCommand(redisClient *c);
void incrbyCommand(redisClient *c); void incrbyCommand(redisClient *c);
...@@ -967,7 +968,6 @@ void discardCommand(redisClient *c); ...@@ -967,7 +968,6 @@ void discardCommand(redisClient *c);
void blpopCommand(redisClient *c); void blpopCommand(redisClient *c);
void brpopCommand(redisClient *c); void brpopCommand(redisClient *c);
void appendCommand(redisClient *c); void appendCommand(redisClient *c);
void substrCommand(redisClient *c);
void strlenCommand(redisClient *c); void strlenCommand(redisClient *c);
void zrankCommand(redisClient *c); void zrankCommand(redisClient *c);
void zrevrankCommand(redisClient *c); void zrevrankCommand(redisClient *c);
......
...@@ -257,6 +257,43 @@ void setrangeCommand(redisClient *c) { ...@@ -257,6 +257,43 @@ void setrangeCommand(redisClient *c) {
addReplyLongLong(c,sdslen(o->ptr)); addReplyLongLong(c,sdslen(o->ptr));
} }
void getrangeCommand(redisClient *c) {
robj *o;
long start, end;
char *str, llbuf[32];
size_t strlen;
if (getLongFromObjectOrReply(c,c->argv[2],&start,NULL) != REDIS_OK)
return;
if (getLongFromObjectOrReply(c,c->argv[3],&end,NULL) != REDIS_OK)
return;
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
checkType(c,o,REDIS_STRING)) return;
if (o->encoding == REDIS_ENCODING_INT) {
str = llbuf;
strlen = ll2string(llbuf,sizeof(llbuf),(long)o->ptr);
} else {
str = o->ptr;
strlen = sdslen(str);
}
/* Convert negative indexes */
if (start < 0) start = strlen+start;
if (end < 0) end = strlen+end;
if (start < 0) start = 0;
if (end < 0) end = 0;
if ((unsigned)end >= strlen) end = strlen-1;
/* Precondition: end >= 0 && end < strlen, so the only condition where
* nothing can be returned is: start > end. */
if (start > end) {
addReply(c,shared.nullbulk);
} else {
addReplyBulkCBuffer(c,(char*)str+start,end-start+1);
}
}
void mgetCommand(redisClient *c) { void mgetCommand(redisClient *c) {
int j; int j;
...@@ -400,43 +437,6 @@ void appendCommand(redisClient *c) { ...@@ -400,43 +437,6 @@ void appendCommand(redisClient *c) {
addReplyLongLong(c,totlen); addReplyLongLong(c,totlen);
} }
void substrCommand(redisClient *c) {
robj *o;
long start = atoi(c->argv[2]->ptr);
long end = atoi(c->argv[3]->ptr);
size_t rangelen, strlen;
sds range;
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
checkType(c,o,REDIS_STRING)) return;
o = getDecodedObject(o);
strlen = sdslen(o->ptr);
/* convert negative indexes */
if (start < 0) start = strlen+start;
if (end < 0) end = strlen+end;
if (start < 0) start = 0;
if (end < 0) end = 0;
/* indexes sanity checks */
if (start > end || (size_t)start >= strlen) {
/* Out of range start or start > end result in null reply */
addReply(c,shared.nullbulk);
decrRefCount(o);
return;
}
if ((size_t)end >= strlen) end = strlen-1;
rangelen = (end-start)+1;
/* Return the result */
addReplySds(c,sdscatprintf(sdsempty(),"$%zu\r\n",rangelen));
range = sdsnewlen((char*)o->ptr+start,rangelen);
addReplySds(c,range);
addReply(c,shared.crlf);
decrRefCount(o);
}
void strlenCommand(redisClient *c) { void strlenCommand(redisClient *c) {
robj *o; robj *o;
......
...@@ -562,4 +562,40 @@ start_server {tags {"basic"}} { ...@@ -562,4 +562,40 @@ start_server {tags {"basic"}} {
r set mykey "hello" r set mykey "hello"
assert_error "*maximum allowed size*" {r setrange mykey [expr 512*1024*1024-4] world} assert_error "*maximum allowed size*" {r setrange mykey [expr 512*1024*1024-4] world}
} }
test {SUBSTR basics} {
set res {}
r set foo "Hello World"
lappend res [r substr foo 0 3]
lappend res [r substr foo 0 -1]
lappend res [r substr foo -4 -1]
lappend res [r substr foo 5 3]
lappend res [r substr foo 5 5000]
lappend res [r substr foo -5000 10000]
set _ $res
} {Hell {Hello World} orld {} { World} {Hello World}}
test {SUBSTR against integer encoded values} {
r set foo 123
r substr foo 0 -2
} {12}
test {SUBSTR fuzzing} {
set err {}
for {set i 0} {$i < 1000} {incr i} {
set bin [randstring 0 1024 binary]
set _start [set start [randomInt 1500]]
set _end [set end [randomInt 1500]]
if {$_start < 0} {set _start "end-[abs($_start)-1]"}
if {$_end < 0} {set _end "end-[abs($_end)-1]"}
set s1 [string range $bin $_start $_end]
r set bin $bin
set s2 [r substr bin $start $end]
if {$s1 != $s2} {
set err "String mismatch"
break
}
}
set _ $err
} {}
} }
...@@ -216,42 +216,6 @@ start_server {tags {"other"}} { ...@@ -216,42 +216,6 @@ start_server {tags {"other"}} {
set _ $err set _ $err
} {} } {}
test {SUBSTR basics} {
set res {}
r set foo "Hello World"
lappend res [r substr foo 0 3]
lappend res [r substr foo 0 -1]
lappend res [r substr foo -4 -1]
lappend res [r substr foo 5 3]
lappend res [r substr foo 5 5000]
lappend res [r substr foo -5000 10000]
set _ $res
} {Hell {Hello World} orld {} { World} {Hello World}}
test {SUBSTR against integer encoded values} {
r set foo 123
r substr foo 0 -2
} {12}
test {SUBSTR fuzzing} {
set err {}
for {set i 0} {$i < 1000} {incr i} {
set bin [randstring 0 1024 binary]
set _start [set start [randomInt 1500]]
set _end [set end [randomInt 1500]]
if {$_start < 0} {set _start "end-[abs($_start)-1]"}
if {$_end < 0} {set _end "end-[abs($_end)-1]"}
set s1 [string range $bin $_start $_end]
r set bin $bin
set s2 [r substr bin $start $end]
if {$s1 != $s2} {
set err "String mismatch"
break
}
}
set _ $err
} {}
# Leave the user with a clean DB before to exit # Leave the user with a clean DB before to exit
test {FLUSHDB} { test {FLUSHDB} {
set aux {} set aux {}
......
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