]>
git.saurik.com Git - redis.git/blob - src/t_string.c
3 /*-----------------------------------------------------------------------------
5 *----------------------------------------------------------------------------*/
7 static int checkStringLength(redisClient
*c
, long long size
) {
8 if (size
> 512*1024*1024) {
9 addReplyError(c
,"string exceeds maximum allowed size (512MB)");
15 void setGenericCommand(redisClient
*c
, int nx
, robj
*key
, robj
*val
, robj
*expire
, int unit
) {
16 long long milliseconds
= 0; /* initialized to avoid an harmness warning */
19 if (getLongLongFromObjectOrReply(c
, expire
, &milliseconds
, NULL
) != REDIS_OK
)
21 if (milliseconds
<= 0) {
22 addReplyError(c
,"invalid expire time in SETEX");
25 if (unit
== UNIT_SECONDS
) milliseconds
*= 1000;
28 if (lookupKeyWrite(c
->db
,key
) != NULL
&& nx
) {
29 addReply(c
,shared
.czero
);
32 setKey(c
->db
,key
,val
);
34 if (expire
) setExpire(c
->db
,key
,mstime()+milliseconds
);
35 addReply(c
, nx
? shared
.cone
: shared
.ok
);
38 void setCommand(redisClient
*c
) {
39 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
40 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[2],NULL
,0);
43 void setnxCommand(redisClient
*c
) {
44 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
45 setGenericCommand(c
,1,c
->argv
[1],c
->argv
[2],NULL
,0);
48 void setexCommand(redisClient
*c
) {
49 c
->argv
[3] = tryObjectEncoding(c
->argv
[3]);
50 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[3],c
->argv
[2],UNIT_SECONDS
);
53 void psetexCommand(redisClient
*c
) {
54 c
->argv
[3] = tryObjectEncoding(c
->argv
[3]);
55 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[3],c
->argv
[2],UNIT_MILLISECONDS
);
58 int getGenericCommand(redisClient
*c
) {
61 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
)
64 if (o
->type
!= REDIS_STRING
) {
65 addReply(c
,shared
.wrongtypeerr
);
73 void getCommand(redisClient
*c
) {
77 void getsetCommand(redisClient
*c
) {
78 if (getGenericCommand(c
) == REDIS_ERR
) return;
79 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
80 setKey(c
->db
,c
->argv
[1],c
->argv
[2]);
84 static int getBitOffsetFromArgument(redisClient
*c
, robj
*o
, size_t *offset
) {
86 char *err
= "bit offset is not an integer or out of range";
88 if (getLongLongFromObjectOrReply(c
,o
,&loffset
,err
) != REDIS_OK
)
91 /* Limit offset to 512MB in bytes */
92 if ((loffset
< 0) || ((unsigned long long)loffset
>> 3) >= (512*1024*1024))
98 *offset
= (size_t)loffset
;
102 void setbitCommand(redisClient
*c
) {
104 char *err
= "bit is not an integer or out of range";
110 if (getBitOffsetFromArgument(c
,c
->argv
[2],&bitoffset
) != REDIS_OK
)
113 if (getLongFromObjectOrReply(c
,c
->argv
[3],&on
,err
) != REDIS_OK
)
116 /* Bits can only be set or cleared... */
118 addReplyError(c
,err
);
122 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
124 o
= createObject(REDIS_STRING
,sdsempty());
125 dbAdd(c
->db
,c
->argv
[1],o
);
127 if (checkType(c
,o
,REDIS_STRING
)) return;
129 /* Create a copy when the object is shared or encoded. */
130 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
131 robj
*decoded
= getDecodedObject(o
);
132 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
133 decrRefCount(decoded
);
134 dbOverwrite(c
->db
,c
->argv
[1],o
);
138 /* Grow sds value to the right length if necessary */
139 byte
= bitoffset
>> 3;
140 o
->ptr
= sdsgrowzero(o
->ptr
,byte
+1);
142 /* Get current values */
143 byteval
= ((char*)o
->ptr
)[byte
];
144 bit
= 7 - (bitoffset
& 0x7);
145 bitval
= byteval
& (1 << bit
);
147 /* Update byte with new bit value and return original value */
148 byteval
&= ~(1 << bit
);
149 byteval
|= ((on
& 0x1) << bit
);
150 ((char*)o
->ptr
)[byte
] = byteval
;
151 signalModifiedKey(c
->db
,c
->argv
[1]);
153 addReply(c
, bitval
? shared
.cone
: shared
.czero
);
156 void getbitCommand(redisClient
*c
) {
163 if (getBitOffsetFromArgument(c
,c
->argv
[2],&bitoffset
) != REDIS_OK
)
166 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
167 checkType(c
,o
,REDIS_STRING
)) return;
169 byte
= bitoffset
>> 3;
170 bit
= 7 - (bitoffset
& 0x7);
171 if (o
->encoding
!= REDIS_ENCODING_RAW
) {
172 if (byte
< (size_t)ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
))
173 bitval
= llbuf
[byte
] & (1 << bit
);
175 if (byte
< sdslen(o
->ptr
))
176 bitval
= ((char*)o
->ptr
)[byte
] & (1 << bit
);
179 addReply(c
, bitval
? shared
.cone
: shared
.czero
);
182 void setrangeCommand(redisClient
*c
) {
185 sds value
= c
->argv
[3]->ptr
;
187 if (getLongFromObjectOrReply(c
,c
->argv
[2],&offset
,NULL
) != REDIS_OK
)
191 addReplyError(c
,"offset is out of range");
195 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
197 /* Return 0 when setting nothing on a non-existing string */
198 if (sdslen(value
) == 0) {
199 addReply(c
,shared
.czero
);
203 /* Return when the resulting string exceeds allowed size */
204 if (checkStringLength(c
,offset
+sdslen(value
)) != REDIS_OK
)
207 o
= createObject(REDIS_STRING
,sdsempty());
208 dbAdd(c
->db
,c
->argv
[1],o
);
212 /* Key exists, check type */
213 if (checkType(c
,o
,REDIS_STRING
))
216 /* Return existing string length when setting nothing */
217 olen
= stringObjectLen(o
);
218 if (sdslen(value
) == 0) {
219 addReplyLongLong(c
,olen
);
223 /* Return when the resulting string exceeds allowed size */
224 if (checkStringLength(c
,offset
+sdslen(value
)) != REDIS_OK
)
227 /* Create a copy when the object is shared or encoded. */
228 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
229 robj
*decoded
= getDecodedObject(o
);
230 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
231 decrRefCount(decoded
);
232 dbOverwrite(c
->db
,c
->argv
[1],o
);
236 if (sdslen(value
) > 0) {
237 o
->ptr
= sdsgrowzero(o
->ptr
,offset
+sdslen(value
));
238 memcpy((char*)o
->ptr
+offset
,value
,sdslen(value
));
239 signalModifiedKey(c
->db
,c
->argv
[1]);
242 addReplyLongLong(c
,sdslen(o
->ptr
));
245 void getrangeCommand(redisClient
*c
) {
248 char *str
, llbuf
[32];
251 if (getLongFromObjectOrReply(c
,c
->argv
[2],&start
,NULL
) != REDIS_OK
)
253 if (getLongFromObjectOrReply(c
,c
->argv
[3],&end
,NULL
) != REDIS_OK
)
255 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.emptybulk
)) == NULL
||
256 checkType(c
,o
,REDIS_STRING
)) return;
258 if (o
->encoding
== REDIS_ENCODING_INT
) {
260 strlen
= ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
);
263 strlen
= sdslen(str
);
266 /* Convert negative indexes */
267 if (start
< 0) start
= strlen
+start
;
268 if (end
< 0) end
= strlen
+end
;
269 if (start
< 0) start
= 0;
270 if (end
< 0) end
= 0;
271 if ((unsigned)end
>= strlen
) end
= strlen
-1;
273 /* Precondition: end >= 0 && end < strlen, so the only condition where
274 * nothing can be returned is: start > end. */
276 addReply(c
,shared
.emptybulk
);
278 addReplyBulkCBuffer(c
,(char*)str
+start
,end
-start
+1);
282 void mgetCommand(redisClient
*c
) {
285 addReplyMultiBulkLen(c
,c
->argc
-1);
286 for (j
= 1; j
< c
->argc
; j
++) {
287 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
289 addReply(c
,shared
.nullbulk
);
291 if (o
->type
!= REDIS_STRING
) {
292 addReply(c
,shared
.nullbulk
);
300 void msetGenericCommand(redisClient
*c
, int nx
) {
303 if ((c
->argc
% 2) == 0) {
304 addReplyError(c
,"wrong number of arguments for MSET");
307 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
308 * set nothing at all if at least one already key exists. */
310 for (j
= 1; j
< c
->argc
; j
+= 2) {
311 if (lookupKeyWrite(c
->db
,c
->argv
[j
]) != NULL
) {
316 addReply(c
, shared
.czero
);
321 for (j
= 1; j
< c
->argc
; j
+= 2) {
322 c
->argv
[j
+1] = tryObjectEncoding(c
->argv
[j
+1]);
323 setKey(c
->db
,c
->argv
[j
],c
->argv
[j
+1]);
325 server
.dirty
+= (c
->argc
-1)/2;
326 addReply(c
, nx
? shared
.cone
: shared
.ok
);
329 void msetCommand(redisClient
*c
) {
330 msetGenericCommand(c
,0);
333 void msetnxCommand(redisClient
*c
) {
334 msetGenericCommand(c
,1);
337 void incrDecrCommand(redisClient
*c
, long long incr
) {
338 long long value
, oldvalue
;
341 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
342 if (o
!= NULL
&& checkType(c
,o
,REDIS_STRING
)) return;
343 if (getLongLongFromObjectOrReply(c
,o
,&value
,NULL
) != REDIS_OK
) return;
347 if ((incr
< 0 && value
> oldvalue
) || (incr
> 0 && value
< oldvalue
)) {
348 addReplyError(c
,"increment or decrement would overflow");
351 new = createStringObjectFromLongLong(value
);
353 dbOverwrite(c
->db
,c
->argv
[1],new);
355 dbAdd(c
->db
,c
->argv
[1],new);
356 signalModifiedKey(c
->db
,c
->argv
[1]);
358 addReply(c
,shared
.colon
);
360 addReply(c
,shared
.crlf
);
363 void incrCommand(redisClient
*c
) {
364 incrDecrCommand(c
,1);
367 void decrCommand(redisClient
*c
) {
368 incrDecrCommand(c
,-1);
371 void incrbyCommand(redisClient
*c
) {
374 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
375 incrDecrCommand(c
,incr
);
378 void decrbyCommand(redisClient
*c
) {
381 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
382 incrDecrCommand(c
,-incr
);
385 void appendCommand(redisClient
*c
) {
389 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
392 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
393 dbAdd(c
->db
,c
->argv
[1],c
->argv
[2]);
394 incrRefCount(c
->argv
[2]);
395 totlen
= stringObjectLen(c
->argv
[2]);
397 /* Key exists, check type */
398 if (checkType(c
,o
,REDIS_STRING
))
401 /* "append" is an argument, so always an sds */
403 totlen
= stringObjectLen(o
)+sdslen(append
->ptr
);
404 if (checkStringLength(c
,totlen
) != REDIS_OK
)
407 /* If the object is shared or encoded, we have to make a copy */
408 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
409 robj
*decoded
= getDecodedObject(o
);
410 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
411 decrRefCount(decoded
);
412 dbOverwrite(c
->db
,c
->argv
[1],o
);
415 /* Append the value */
416 o
->ptr
= sdscatlen(o
->ptr
,append
->ptr
,sdslen(append
->ptr
));
417 totlen
= sdslen(o
->ptr
);
419 signalModifiedKey(c
->db
,c
->argv
[1]);
421 addReplyLongLong(c
,totlen
);
424 void strlenCommand(redisClient
*c
) {
426 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
427 checkType(c
,o
,REDIS_STRING
)) return;
428 addReplyLongLong(c
,stringObjectLen(o
));