Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
57997664
Commit
57997664
authored
Dec 14, 2010
by
antirez
Browse files
Merge remote branch 'pietern/strrange'
parents
8c304be3
d8f160a8
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/redis.c
View file @
57997664
...
@@ -74,10 +74,14 @@ struct redisCommand readonlyCommandTable[] = {
...
@@ -74,10 +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
},
{
"getbit"
,
getbitCommand
,
3
,
0
,
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
},
...
...
src/redis.h
View file @
57997664
...
@@ -890,6 +890,10 @@ void setexCommand(redisClient *c);
...
@@ -890,6 +890,10 @@ void setexCommand(redisClient *c);
void
getCommand
(
redisClient
*
c
);
void
getCommand
(
redisClient
*
c
);
void
delCommand
(
redisClient
*
c
);
void
delCommand
(
redisClient
*
c
);
void
existsCommand
(
redisClient
*
c
);
void
existsCommand
(
redisClient
*
c
);
void
setbitCommand
(
redisClient
*
c
);
void
getbitCommand
(
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 +971,6 @@ void discardCommand(redisClient *c);
...
@@ -967,7 +971,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
);
...
...
src/sds.c
View file @
57997664
...
@@ -116,6 +116,25 @@ static sds sdsMakeRoomFor(sds s, size_t addlen) {
...
@@ -116,6 +116,25 @@ static sds sdsMakeRoomFor(sds s, size_t addlen) {
return
newsh
->
buf
;
return
newsh
->
buf
;
}
}
/* Grow the sds to have the specified length. Bytes that were not part of
* the original length of the sds will be set to zero. */
sds
sdsgrowzero
(
sds
s
,
size_t
len
)
{
struct
sdshdr
*
sh
=
(
void
*
)(
s
-
(
sizeof
(
struct
sdshdr
)));
size_t
totlen
,
curlen
=
sh
->
len
;
if
(
len
<=
curlen
)
return
s
;
s
=
sdsMakeRoomFor
(
s
,
len
-
curlen
);
if
(
s
==
NULL
)
return
NULL
;
/* Make sure added region doesn't contain garbage */
sh
=
(
void
*
)(
s
-
(
sizeof
(
struct
sdshdr
)));
memset
(
s
+
curlen
,
0
,(
len
-
curlen
+
1
));
/* also set trailing \0 byte */
totlen
=
sh
->
len
+
sh
->
free
;
sh
->
len
=
len
;
sh
->
free
=
totlen
-
sh
->
len
;
return
s
;
}
sds
sdscatlen
(
sds
s
,
void
*
t
,
size_t
len
)
{
sds
sdscatlen
(
sds
s
,
void
*
t
,
size_t
len
)
{
struct
sdshdr
*
sh
;
struct
sdshdr
*
sh
;
size_t
curlen
=
sdslen
(
s
);
size_t
curlen
=
sdslen
(
s
);
...
...
src/sds.h
View file @
57997664
...
@@ -49,6 +49,7 @@ size_t sdslen(const sds s);
...
@@ -49,6 +49,7 @@ size_t sdslen(const sds s);
sds
sdsdup
(
const
sds
s
);
sds
sdsdup
(
const
sds
s
);
void
sdsfree
(
sds
s
);
void
sdsfree
(
sds
s
);
size_t
sdsavail
(
sds
s
);
size_t
sdsavail
(
sds
s
);
sds
sdsgrowzero
(
sds
s
,
size_t
len
);
sds
sdscatlen
(
sds
s
,
void
*
t
,
size_t
len
);
sds
sdscatlen
(
sds
s
,
void
*
t
,
size_t
len
);
sds
sdscat
(
sds
s
,
char
*
t
);
sds
sdscat
(
sds
s
,
char
*
t
);
sds
sdscpylen
(
sds
s
,
char
*
t
,
size_t
len
);
sds
sdscpylen
(
sds
s
,
char
*
t
,
size_t
len
);
...
...
src/t_string.c
View file @
57997664
#include <limits.h>
#include "redis.h"
#include "redis.h"
/*-----------------------------------------------------------------------------
/*-----------------------------------------------------------------------------
* String Commands
* String Commands
*----------------------------------------------------------------------------*/
*----------------------------------------------------------------------------*/
static
int
checkStringLength
(
redisClient
*
c
,
long
long
size
)
{
if
(
size
>
512
*
1024
*
1024
)
{
addReplyError
(
c
,
"string exceeds maximum allowed size (512MB)"
);
return
REDIS_ERR
;
}
return
REDIS_OK
;
}
void
setGenericCommand
(
redisClient
*
c
,
int
nx
,
robj
*
key
,
robj
*
val
,
robj
*
expire
)
{
void
setGenericCommand
(
redisClient
*
c
,
int
nx
,
robj
*
key
,
robj
*
val
,
robj
*
expire
)
{
int
retval
;
int
retval
;
long
seconds
=
0
;
/* initialized to avoid an harmness warning */
long
seconds
=
0
;
/* initialized to avoid an harmness warning */
...
@@ -80,6 +89,211 @@ void getsetCommand(redisClient *c) {
...
@@ -80,6 +89,211 @@ void getsetCommand(redisClient *c) {
removeExpire
(
c
->
db
,
c
->
argv
[
1
]);
removeExpire
(
c
->
db
,
c
->
argv
[
1
]);
}
}
static
int
getBitOffsetFromArgument
(
redisClient
*
c
,
robj
*
o
,
size_t
*
offset
)
{
long
long
loffset
;
char
*
err
=
"bit offset is not an integer or out of range"
;
if
(
getLongLongFromObjectOrReply
(
c
,
o
,
&
loffset
,
err
)
!=
REDIS_OK
)
return
REDIS_ERR
;
/* Limit offset to SIZE_T_MAX or 512MB in bytes */
if
((
loffset
<
0
)
||
((
unsigned
long
long
)
loffset
>=
(
unsigned
)
SIZE_T_MAX
)
||
((
unsigned
long
long
)
loffset
>>
3
)
>=
(
512
*
1024
*
1024
))
{
addReplyError
(
c
,
err
);
return
REDIS_ERR
;
}
*
offset
=
(
size_t
)
loffset
;
return
REDIS_OK
;
}
void
setbitCommand
(
redisClient
*
c
)
{
robj
*
o
;
char
*
err
=
"bit is not an integer or out of range"
;
size_t
bitoffset
;
long
long
bitvalue
;
int
byte
,
bit
,
on
;
if
(
getBitOffsetFromArgument
(
c
,
c
->
argv
[
2
],
&
bitoffset
)
!=
REDIS_OK
)
return
;
if
(
getLongLongFromObjectOrReply
(
c
,
c
->
argv
[
3
],
&
bitvalue
,
err
)
!=
REDIS_OK
)
return
;
/* A bit can only be set to be on or off... */
if
(
bitvalue
&
~
1
)
{
addReplyError
(
c
,
err
);
return
;
}
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
if
(
o
==
NULL
)
{
o
=
createObject
(
REDIS_STRING
,
sdsempty
());
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
o
);
}
else
{
if
(
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
/* Create a copy when the object is shared or encoded. */
if
(
o
->
refcount
!=
1
||
o
->
encoding
!=
REDIS_ENCODING_RAW
)
{
robj
*
decoded
=
getDecodedObject
(
o
);
o
=
createStringObject
(
decoded
->
ptr
,
sdslen
(
decoded
->
ptr
));
decrRefCount
(
decoded
);
dbReplace
(
c
->
db
,
c
->
argv
[
1
],
o
);
}
}
byte
=
bitoffset
>>
3
;
bit
=
7
-
(
bitoffset
&
0x7
);
on
=
bitvalue
&
0x1
;
o
->
ptr
=
sdsgrowzero
(
o
->
ptr
,
byte
+
1
);
((
char
*
)
o
->
ptr
)[
byte
]
|=
on
<<
bit
;
((
char
*
)
o
->
ptr
)[
byte
]
&=
~
((
!
on
)
<<
bit
);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
addReply
(
c
,
shared
.
cone
);
}
void
getbitCommand
(
redisClient
*
c
)
{
robj
*
o
;
size_t
bitoffset
,
byte
,
bitmask
;
int
on
=
0
;
char
llbuf
[
32
];
if
(
getBitOffsetFromArgument
(
c
,
c
->
argv
[
2
],
&
bitoffset
)
!=
REDIS_OK
)
return
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
byte
=
bitoffset
>>
3
;
bitmask
=
1
<<
(
7
-
(
bitoffset
&
0x7
));
if
(
o
->
encoding
!=
REDIS_ENCODING_RAW
)
{
if
(
byte
<
(
size_t
)
ll2string
(
llbuf
,
sizeof
(
llbuf
),(
long
)
o
->
ptr
))
on
=
llbuf
[
byte
]
&
bitmask
;
}
else
{
if
(
byte
<
sdslen
(
o
->
ptr
))
on
=
((
sds
)
o
->
ptr
)[
byte
]
&
bitmask
;
}
addReply
(
c
,
on
?
shared
.
cone
:
shared
.
czero
);
}
void
setrangeCommand
(
redisClient
*
c
)
{
robj
*
o
;
long
offset
;
sds
value
=
c
->
argv
[
3
]
->
ptr
;
if
(
getLongFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
offset
,
NULL
)
!=
REDIS_OK
)
return
;
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
if
(
o
==
NULL
)
{
/* Negative offset is always 0 for non-existing keys */
if
(
offset
<
0
)
offset
=
0
;
/* Return 0 when setting nothing on a non-existing string */
if
(
sdslen
(
value
)
==
0
)
{
addReply
(
c
,
shared
.
czero
);
return
;
}
/* Return when the resulting string exceeds allowed size */
if
(
checkStringLength
(
c
,
offset
+
sdslen
(
value
))
!=
REDIS_OK
)
return
;
o
=
createObject
(
REDIS_STRING
,
sdsempty
());
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
o
);
}
else
{
int
olen
;
/* Key exists, check type */
if
(
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
/* Find out existing value length */
if
(
o
->
encoding
==
REDIS_ENCODING_INT
)
{
char
llbuf
[
32
];
olen
=
ll2string
(
llbuf
,
sizeof
(
llbuf
),(
long
)
o
->
ptr
);
}
else
{
olen
=
sdslen
(
o
->
ptr
);
}
/* Return existing string length when setting nothing */
if
(
sdslen
(
value
)
==
0
)
{
addReplyLongLong
(
c
,
olen
);
return
;
}
/* Convert negative indexes. Note that for SETRANGE, the meaning of a
* negative index is a little different than for other commands.
* Here, an offset of -1 points to the trailing NULL byte of the
* string instead of the last character. */
if
(
offset
<
0
)
{
offset
=
olen
+
1
+
offset
;
if
(
offset
<
0
)
offset
=
0
;
}
/* Return when the resulting string exceeds allowed size */
if
(
checkStringLength
(
c
,
offset
+
sdslen
(
value
))
!=
REDIS_OK
)
return
;
/* Create a copy when the object is shared or encoded. */
if
(
o
->
refcount
!=
1
||
o
->
encoding
!=
REDIS_ENCODING_RAW
)
{
robj
*
decoded
=
getDecodedObject
(
o
);
o
=
createStringObject
(
decoded
->
ptr
,
sdslen
(
decoded
->
ptr
));
decrRefCount
(
decoded
);
dbReplace
(
c
->
db
,
c
->
argv
[
1
],
o
);
}
}
if
(
sdslen
(
value
)
>
0
)
{
o
->
ptr
=
sdsgrowzero
(
o
->
ptr
,
offset
+
sdslen
(
value
));
memcpy
((
char
*
)
o
->
ptr
+
offset
,
value
,
sdslen
(
value
));
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
}
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
;
...
@@ -181,7 +395,7 @@ void decrbyCommand(redisClient *c) {
...
@@ -181,7 +395,7 @@ void decrbyCommand(redisClient *c) {
void
appendCommand
(
redisClient
*
c
)
{
void
appendCommand
(
redisClient
*
c
)
{
int
retval
;
int
retval
;
size_t
totlen
;
size_t
totlen
;
robj
*
o
;
robj
*
o
,
*
append
;
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
...
@@ -195,23 +409,27 @@ void appendCommand(redisClient *c) {
...
@@ -195,23 +409,27 @@ void appendCommand(redisClient *c) {
addReply
(
c
,
shared
.
wrongtypeerr
);
addReply
(
c
,
shared
.
wrongtypeerr
);
return
;
return
;
}
}
/* If the object is specially encoded or shared we have to make
* a copy */
append
=
getDecodedObject
(
c
->
argv
[
2
]);
if
(
o
->
encoding
==
REDIS_ENCODING_RAW
&&
(
sdslen
(
o
->
ptr
)
+
sdslen
(
append
->
ptr
))
>
512
*
1024
*
1024
)
{
addReplyError
(
c
,
"string exceeds maximum allowed size (512MB)"
);
decrRefCount
(
append
);
return
;
}
/* If the object is shared or encoded, we have to make a copy */
if
(
o
->
refcount
!=
1
||
o
->
encoding
!=
REDIS_ENCODING_RAW
)
{
if
(
o
->
refcount
!=
1
||
o
->
encoding
!=
REDIS_ENCODING_RAW
)
{
robj
*
decoded
=
getDecodedObject
(
o
);
robj
*
decoded
=
getDecodedObject
(
o
);
o
=
createStringObject
(
decoded
->
ptr
,
sdslen
(
decoded
->
ptr
));
o
=
createStringObject
(
decoded
->
ptr
,
sdslen
(
decoded
->
ptr
));
decrRefCount
(
decoded
);
decrRefCount
(
decoded
);
dbReplace
(
c
->
db
,
c
->
argv
[
1
],
o
);
dbReplace
(
c
->
db
,
c
->
argv
[
1
],
o
);
}
}
/* APPEND! */
if
(
c
->
argv
[
2
]
->
encoding
==
REDIS_ENCODING_RAW
)
{
/* Append the value */
o
->
ptr
=
sdscatlen
(
o
->
ptr
,
o
->
ptr
=
sdscatlen
(
o
->
ptr
,
append
->
ptr
,
sdslen
(
append
->
ptr
));
c
->
argv
[
2
]
->
ptr
,
sdslen
(
c
->
argv
[
2
]
->
ptr
));
decrRefCount
(
append
);
}
else
{
o
->
ptr
=
sdscatprintf
(
o
->
ptr
,
"%ld"
,
(
unsigned
long
)
c
->
argv
[
2
]
->
ptr
);
}
totlen
=
sdslen
(
o
->
ptr
);
totlen
=
sdslen
(
o
->
ptr
);
}
}
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
...
@@ -219,50 +437,20 @@ void appendCommand(redisClient *c) {
...
@@ -219,50 +437,20 @@ 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
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
o
=
getDecodedObject
(
o
);
if
(
o
->
encoding
==
REDIS_ENCODING_RAW
)
{
addReplyLongLong
(
c
,
sdslen
(
o
->
ptr
));
addReplyLongLong
(
c
,
sdslen
(
o
->
ptr
));
decrRefCount
(
o
);
}
else
if
(
o
->
encoding
==
REDIS_ENCODING_INT
)
{
char
llbuf
[
32
];
int
len
=
ll2string
(
llbuf
,
sizeof
(
llbuf
),(
long
)
o
->
ptr
);
addReplyLongLong
(
c
,
len
);
}
else
{
redisPanic
(
"Unknown string encoding"
);
}
}
}
tests/unit/basic.tcl
View file @
57997664
...
@@ -374,4 +374,228 @@ start_server {tags {"basic"}} {
...
@@ -374,4 +374,228 @@ start_server {tags {"basic"}} {
r set mystring
"foozzz0123456789 baz"
r set mystring
"foozzz0123456789 baz"
r strlen mystring
r strlen mystring
}
}
test
"SETBIT against non-existing key"
{
r del mykey
# Setting 2nd bit to on is integer 64, ascii
"@"
assert_equal 1
[
r setbit mykey 1 1
]
assert_equal
"@"
[
r get mykey
]
}
test
"SETBIT against string-encoded key"
{
# Single byte with 2nd bit set
r set mykey
"@"
# 64 + 32 = 96 => ascii
"`"
(
backtick
)
assert_equal 1
[
r setbit mykey 2 1
]
assert_equal
"`"
[
r get mykey
]
}
test
"SETBIT against integer-encoded key"
{
r set mykey 1
assert_encoding int mykey
# Ascii
"1"
is integer 49 = 00 11 00 01
# Setting 7th bit = 51 => ascii
"3"
assert_equal 1
[
r setbit mykey 6 1
]
assert_equal
"3"
[
r get mykey
]
}
test
"SETBIT against key with wrong type"
{
r del mykey
r lpush mykey
"foo"
assert_error
"*wrong kind*"
{
r setbit mykey 0 1
}
}
test
"SETBIT with out of range bit offset"
{
r del mykey
assert_error
"*out of range*"
{
r setbit mykey
[
expr 4*1024*1024*1024
]
1
}
assert_error
"*out of range*"
{
r setbit mykey -1 1
}
}
test
"SETBIT with non-bit argument"
{
r del mykey
assert_error
"*out of range*"
{
r setbit mykey 0 -1
}
assert_error
"*out of range*"
{
r setbit mykey 0 2
}
assert_error
"*out of range*"
{
r setbit mykey 0 10
}
assert_error
"*out of range*"
{
r setbit mykey 0 20
}
}
test
"GETBIT against non-existing key"
{
r del mykey
assert_equal 0
[
r getbit mykey 0
]
}
test
"GETBIT against string-encoded key"
{
# Single byte with 2nd and 3rd bit set
r set mykey
"`"
# In-range
assert_equal 0
[
r getbit mykey 0
]
assert_equal 1
[
r getbit mykey 1
]
assert_equal 1
[
r getbit mykey 2
]
assert_equal 0
[
r getbit mykey 3
]
# Out-range
assert_equal 0
[
r getbit mykey 8
]
assert_equal 0
[
r getbit mykey 100
]
assert_equal 0
[
r getbit mykey 10000
]
}
test
"GETBIT against integer-encoded key"
{
r set mykey 1
assert_encoding int mykey
# Ascii
"1"
is integer 49 = 00 11 00 01
assert_equal 0
[
r getbit mykey 0
]
assert_equal 0
[
r getbit mykey 1
]
assert_equal 1
[
r getbit mykey 2
]
assert_equal 1
[
r getbit mykey 3
]
# Out-range
assert_equal 0
[
r getbit mykey 8
]
assert_equal 0
[
r getbit mykey 100
]
assert_equal 0
[
r getbit mykey 10000
]
}
test
"SETRANGE against non-existing key"
{
r del mykey
assert_equal 3
[
r setrange mykey 0 foo
]
assert_equal
"foo"
[
r get mykey
]
r del mykey
assert_equal 0
[
r setrange mykey 0
""
]
assert_equal 0
[
r exists mykey
]
r del mykey
assert_equal 4
[
r setrange mykey 1 foo
]
assert_equal
"
\000
foo"
[
r get mykey
]
r del mykey
assert_equal 3
[
r setrange mykey -1 foo
]
assert_equal
"foo"
[
r get mykey
]
r del mykey
assert_equal 3
[
r setrange mykey -100 foo
]
assert_equal
"foo"
[
r get mykey
]
}
test
"SETRANGE against string-encoded key"
{
r set mykey
"foo"
assert_equal 3
[
r setrange mykey 0 b
]
assert_equal
"boo"
[
r get mykey
]
r set mykey
"foo"
assert_equal 3
[
r setrange mykey 0
""
]
assert_equal
"foo"
[
r get mykey
]
r set mykey
"foo"
assert_equal 3
[
r setrange mykey 1 b
]
assert_equal
"fbo"
[
r get mykey
]
r set mykey
"foo"
assert_equal 6
[
r setrange mykey -1 bar
]
assert_equal
"foobar"
[
r get mykey
]
r set mykey
"foo"
assert_equal 5
[
r setrange mykey -2 bar
]
assert_equal
"fobar"
[
r get mykey
]
r set mykey
"foo"
assert_equal 3
[
r setrange mykey -20 bar
]
assert_equal
"bar"
[
r get mykey
]
r set mykey
"foo"
assert_equal 7
[
r setrange mykey 4 bar
]
assert_equal
"foo
\000
bar"
[
r get mykey
]
}
test
"SETRANGE against integer-encoded key"
{
r set mykey 1234
assert_encoding int mykey
assert_equal 4
[
r setrange mykey 0 2
]
assert_encoding raw mykey
assert_equal 2234
[
r get mykey
]
# Shouldn't change encoding when nothing is set
r set mykey 1234
assert_encoding int mykey
assert_equal 4
[
r setrange mykey 0
""
]
assert_encoding int mykey
assert_equal 1234
[
r get mykey
]
r set mykey 1234
assert_encoding int mykey
assert_equal 4
[
r setrange mykey 1 3
]
assert_encoding raw mykey
assert_equal 1334
[
r get mykey
]
r set mykey 1234
assert_encoding int mykey
assert_equal 5
[
r setrange mykey -1 5
]
assert_encoding raw mykey
assert_equal 12345
[
r get mykey
]
r set mykey 1234
assert_encoding int mykey
assert_equal 4
[
r setrange mykey -2 5
]
assert_encoding raw mykey
assert_equal 1235
[
r get mykey
]
r set mykey 1234
assert_encoding int mykey
assert_equal 6
[
r setrange mykey 5 2
]
assert_encoding raw mykey
assert_equal
"1234
\000
2"
[
r get mykey
]
}
test
"SETRANGE against key with wrong type"
{
r del mykey
r lpush mykey
"foo"
assert_error
"*wrong kind*"
{
r setrange mykey 0 bar
}
}
test
"SETRANGE with out of range offset"
{
r del mykey
assert_error
"*maximum allowed size*"
{
r setrange mykey
[
expr 512*1024*1024-4
]
world
}
r set mykey
"hello"
assert_error
"*maximum allowed size*"
{
r setrange mykey
[
expr 512*1024*1024-4
]
world
}
}
test
"GETRANGE against non-existing key"
{
r del mykey
assert_equal
""
[
r getrange mykey 0 -1
]
}
test
"GETRANGE against string value"
{
r set mykey
"Hello World"
assert_equal
"Hell"
[
r getrange mykey 0 3
]
assert_equal
"Hello World"
[
r getrange mykey 0 -1
]
assert_equal
"orld"
[
r getrange mykey -4 -1
]
assert_equal
""
[
r getrange mykey 5 3
]
assert_equal
" World"
[
r getrange mykey 5 5000
]
assert_equal
"Hello World"
[
r getrange mykey -5000 10000
]
}
test
"GETRANGE against integer-encoded value"
{
r set mykey 1234
assert_equal
"123"
[
r getrange mykey 0 2
]
assert_equal
"1234"
[
r getrange mykey 0 -1
]
assert_equal
"234"
[
r getrange mykey -3 -1
]
assert_equal
""
[
r getrange mykey 5 3
]
assert_equal
"4"
[
r getrange mykey 3 5000
]
assert_equal
"1234"
[
r getrange mykey -5000 10000
]
}
test
"GETRANGE fuzzing"
{
for
{
set i 0
}
{
$i
< 1000
}
{
incr i
}
{
r set bin
[
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
]
"
}
assert_equal
[
string range $bin $_start $_end
]
[
r getrange bin $start $end
]
}
}
}
}
tests/unit/other.tcl
View file @
57997664
...
@@ -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
{}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment