]>
git.saurik.com Git - redis.git/blob - src/t_string.c
4 /*-----------------------------------------------------------------------------
6 *----------------------------------------------------------------------------*/
8 static int checkStringLength(redisClient
*c
, long long size
) {
9 if (size
> 512*1024*1024) {
10 addReplyError(c
,"string exceeds maximum allowed size (512MB)");
16 void setGenericCommand(redisClient
*c
, int nx
, robj
*key
, robj
*val
, robj
*expire
) {
18 long seconds
= 0; /* initialized to avoid an harmness warning */
21 if (getLongFromObjectOrReply(c
, expire
, &seconds
, NULL
) != REDIS_OK
)
24 addReplyError(c
,"invalid expire time in SETEX");
29 retval
= dbAdd(c
->db
,key
,val
);
30 if (retval
== REDIS_ERR
) {
32 dbReplace(c
->db
,key
,val
);
35 addReply(c
,shared
.czero
);
41 touchWatchedKey(c
->db
,key
);
43 removeExpire(c
->db
,key
);
44 if (expire
) setExpire(c
->db
,key
,time(NULL
)+seconds
);
45 addReply(c
, nx
? shared
.cone
: shared
.ok
);
48 void setCommand(redisClient
*c
) {
49 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
50 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[2],NULL
);
53 void setnxCommand(redisClient
*c
) {
54 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
55 setGenericCommand(c
,1,c
->argv
[1],c
->argv
[2],NULL
);
58 void setexCommand(redisClient
*c
) {
59 c
->argv
[3] = tryObjectEncoding(c
->argv
[3]);
60 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[3],c
->argv
[2]);
63 int getGenericCommand(redisClient
*c
) {
66 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
)
69 if (o
->type
!= REDIS_STRING
) {
70 addReply(c
,shared
.wrongtypeerr
);
78 void getCommand(redisClient
*c
) {
82 void getsetCommand(redisClient
*c
) {
83 if (getGenericCommand(c
) == REDIS_ERR
) return;
84 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
85 dbReplace(c
->db
,c
->argv
[1],c
->argv
[2]);
86 incrRefCount(c
->argv
[2]);
87 touchWatchedKey(c
->db
,c
->argv
[1]);
89 removeExpire(c
->db
,c
->argv
[1]);
92 static int getBitOffsetFromArgument(redisClient
*c
, robj
*o
, size_t *offset
) {
94 char *err
= "bit offset is not an integer or out of range";
96 if (getLongLongFromObjectOrReply(c
,o
,&loffset
,err
) != REDIS_OK
)
99 /* Limit offset to 512MB in bytes */
100 if ((loffset
< 0) || ((unsigned long long)loffset
>> 3) >= (512*1024*1024))
102 addReplyError(c
,err
);
106 *offset
= (size_t)loffset
;
110 void setbitCommand(redisClient
*c
) {
112 char *err
= "bit is not an integer or out of range";
118 if (getBitOffsetFromArgument(c
,c
->argv
[2],&bitoffset
) != REDIS_OK
)
121 if (getLongFromObjectOrReply(c
,c
->argv
[3],&on
,err
) != REDIS_OK
)
124 /* Bits can only be set or cleared... */
126 addReplyError(c
,err
);
130 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
132 o
= createObject(REDIS_STRING
,sdsempty());
133 dbAdd(c
->db
,c
->argv
[1],o
);
135 if (checkType(c
,o
,REDIS_STRING
)) return;
137 /* Create a copy when the object is shared or encoded. */
138 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
139 robj
*decoded
= getDecodedObject(o
);
140 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
141 decrRefCount(decoded
);
142 dbReplace(c
->db
,c
->argv
[1],o
);
146 /* Grow sds value to the right length if necessary */
147 byte
= bitoffset
>> 3;
148 o
->ptr
= sdsgrowzero(o
->ptr
,byte
+1);
150 /* Get current values */
151 byteval
= ((char*)o
->ptr
)[byte
];
152 bit
= 7 - (bitoffset
& 0x7);
153 bitval
= byteval
& (1 << bit
);
155 /* Update byte with new bit value and return original value */
156 byteval
&= ~(1 << bit
);
157 byteval
|= ((on
& 0x1) << bit
);
158 ((char*)o
->ptr
)[byte
] = byteval
;
159 touchWatchedKey(c
->db
,c
->argv
[1]);
161 addReply(c
, bitval
? shared
.cone
: shared
.czero
);
164 void getbitCommand(redisClient
*c
) {
171 if (getBitOffsetFromArgument(c
,c
->argv
[2],&bitoffset
) != REDIS_OK
)
174 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
175 checkType(c
,o
,REDIS_STRING
)) return;
177 byte
= bitoffset
>> 3;
178 bit
= 7 - (bitoffset
& 0x7);
179 if (o
->encoding
!= REDIS_ENCODING_RAW
) {
180 if (byte
< (size_t)ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
))
181 bitval
= llbuf
[byte
] & (1 << bit
);
183 if (byte
< sdslen(o
->ptr
))
184 bitval
= ((char*)o
->ptr
)[byte
] & (1 << bit
);
187 addReply(c
, bitval
? shared
.cone
: shared
.czero
);
190 void setrangeCommand(redisClient
*c
) {
193 sds value
= c
->argv
[3]->ptr
;
195 if (getLongFromObjectOrReply(c
,c
->argv
[2],&offset
,NULL
) != REDIS_OK
)
198 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
200 /* Negative offset is always 0 for non-existing keys */
201 if (offset
< 0) offset
= 0;
203 /* Return 0 when setting nothing on a non-existing string */
204 if (sdslen(value
) == 0) {
205 addReply(c
,shared
.czero
);
209 /* Return when the resulting string exceeds allowed size */
210 if (checkStringLength(c
,offset
+sdslen(value
)) != REDIS_OK
)
213 o
= createObject(REDIS_STRING
,sdsempty());
214 dbAdd(c
->db
,c
->argv
[1],o
);
218 /* Key exists, check type */
219 if (checkType(c
,o
,REDIS_STRING
))
222 /* Find out existing value length */
223 if (o
->encoding
== REDIS_ENCODING_INT
) {
225 olen
= ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
);
227 olen
= sdslen(o
->ptr
);
230 /* Return existing string length when setting nothing */
231 if (sdslen(value
) == 0) {
232 addReplyLongLong(c
,olen
);
236 /* Convert negative indexes. Note that for SETRANGE, the meaning of a
237 * negative index is a little different than for other commands.
238 * Here, an offset of -1 points to the trailing NULL byte of the
239 * string instead of the last character. */
241 offset
= olen
+1+offset
;
242 if (offset
< 0) offset
= 0;
245 /* Return when the resulting string exceeds allowed size */
246 if (checkStringLength(c
,offset
+sdslen(value
)) != REDIS_OK
)
249 /* Create a copy when the object is shared or encoded. */
250 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
251 robj
*decoded
= getDecodedObject(o
);
252 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
253 decrRefCount(decoded
);
254 dbReplace(c
->db
,c
->argv
[1],o
);
258 if (sdslen(value
) > 0) {
259 o
->ptr
= sdsgrowzero(o
->ptr
,offset
+sdslen(value
));
260 memcpy((char*)o
->ptr
+offset
,value
,sdslen(value
));
261 touchWatchedKey(c
->db
,c
->argv
[1]);
264 addReplyLongLong(c
,sdslen(o
->ptr
));
267 void getrangeCommand(redisClient
*c
) {
270 char *str
, llbuf
[32];
273 if (getLongFromObjectOrReply(c
,c
->argv
[2],&start
,NULL
) != REDIS_OK
)
275 if (getLongFromObjectOrReply(c
,c
->argv
[3],&end
,NULL
) != REDIS_OK
)
277 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
278 checkType(c
,o
,REDIS_STRING
)) return;
280 if (o
->encoding
== REDIS_ENCODING_INT
) {
282 strlen
= ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
);
285 strlen
= sdslen(str
);
288 /* Convert negative indexes */
289 if (start
< 0) start
= strlen
+start
;
290 if (end
< 0) end
= strlen
+end
;
291 if (start
< 0) start
= 0;
292 if (end
< 0) end
= 0;
293 if ((unsigned)end
>= strlen
) end
= strlen
-1;
295 /* Precondition: end >= 0 && end < strlen, so the only condition where
296 * nothing can be returned is: start > end. */
298 addReply(c
,shared
.nullbulk
);
300 addReplyBulkCBuffer(c
,(char*)str
+start
,end
-start
+1);
304 void mgetCommand(redisClient
*c
) {
307 addReplyMultiBulkLen(c
,c
->argc
-1);
308 for (j
= 1; j
< c
->argc
; j
++) {
309 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
311 addReply(c
,shared
.nullbulk
);
313 if (o
->type
!= REDIS_STRING
) {
314 addReply(c
,shared
.nullbulk
);
322 void msetGenericCommand(redisClient
*c
, int nx
) {
325 if ((c
->argc
% 2) == 0) {
326 addReplyError(c
,"wrong number of arguments for MSET");
329 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
330 * set nothing at all if at least one already key exists. */
332 for (j
= 1; j
< c
->argc
; j
+= 2) {
333 if (lookupKeyWrite(c
->db
,c
->argv
[j
]) != NULL
) {
339 addReply(c
, shared
.czero
);
343 for (j
= 1; j
< c
->argc
; j
+= 2) {
344 c
->argv
[j
+1] = tryObjectEncoding(c
->argv
[j
+1]);
345 dbReplace(c
->db
,c
->argv
[j
],c
->argv
[j
+1]);
346 incrRefCount(c
->argv
[j
+1]);
347 removeExpire(c
->db
,c
->argv
[j
]);
348 touchWatchedKey(c
->db
,c
->argv
[j
]);
350 server
.dirty
+= (c
->argc
-1)/2;
351 addReply(c
, nx
? shared
.cone
: shared
.ok
);
354 void msetCommand(redisClient
*c
) {
355 msetGenericCommand(c
,0);
358 void msetnxCommand(redisClient
*c
) {
359 msetGenericCommand(c
,1);
362 void incrDecrCommand(redisClient
*c
, long long incr
) {
366 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
367 if (o
!= NULL
&& checkType(c
,o
,REDIS_STRING
)) return;
368 if (getLongLongFromObjectOrReply(c
,o
,&value
,NULL
) != REDIS_OK
) return;
371 o
= createStringObjectFromLongLong(value
);
372 dbReplace(c
->db
,c
->argv
[1],o
);
373 touchWatchedKey(c
->db
,c
->argv
[1]);
375 addReply(c
,shared
.colon
);
377 addReply(c
,shared
.crlf
);
380 void incrCommand(redisClient
*c
) {
381 incrDecrCommand(c
,1);
384 void decrCommand(redisClient
*c
) {
385 incrDecrCommand(c
,-1);
388 void incrbyCommand(redisClient
*c
) {
391 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
392 incrDecrCommand(c
,incr
);
395 void decrbyCommand(redisClient
*c
) {
398 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
399 incrDecrCommand(c
,-incr
);
402 void appendCommand(redisClient
*c
) {
407 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
408 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
411 retval
= dbAdd(c
->db
,c
->argv
[1],c
->argv
[2]);
412 incrRefCount(c
->argv
[2]);
413 totlen
= stringObjectLen(c
->argv
[2]);
415 if (o
->type
!= REDIS_STRING
) {
416 addReply(c
,shared
.wrongtypeerr
);
420 append
= getDecodedObject(c
->argv
[2]);
421 if (o
->encoding
== REDIS_ENCODING_RAW
&&
422 (sdslen(o
->ptr
) + sdslen(append
->ptr
)) > 512*1024*1024)
424 addReplyError(c
,"string exceeds maximum allowed size (512MB)");
425 decrRefCount(append
);
429 /* If the object is shared or encoded, we have to make a copy */
430 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
431 robj
*decoded
= getDecodedObject(o
);
432 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
433 decrRefCount(decoded
);
434 dbReplace(c
->db
,c
->argv
[1],o
);
437 /* Append the value */
438 o
->ptr
= sdscatlen(o
->ptr
,append
->ptr
,sdslen(append
->ptr
));
439 decrRefCount(append
);
440 totlen
= sdslen(o
->ptr
);
442 touchWatchedKey(c
->db
,c
->argv
[1]);
444 addReplyLongLong(c
,totlen
);
447 void strlenCommand(redisClient
*c
) {
450 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
451 checkType(c
,o
,REDIS_STRING
)) return;
453 if (o
->encoding
== REDIS_ENCODING_RAW
) {
454 addReplyLongLong(c
,sdslen(o
->ptr
));
455 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
457 int len
= ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
);
458 addReplyLongLong(c
,len
);
460 redisPanic("Unknown string encoding");