]>
git.saurik.com Git - redis.git/blob - src/t_string.c
2 #include <math.h> /* isnan(), isinf() */
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
, int unit
) {
17 long long milliseconds
= 0; /* initialized to avoid an harmness warning */
20 if (getLongLongFromObjectOrReply(c
, expire
, &milliseconds
, NULL
) != REDIS_OK
)
22 if (milliseconds
<= 0) {
23 addReplyError(c
,"invalid expire time in SETEX");
26 if (unit
== UNIT_SECONDS
) milliseconds
*= 1000;
29 if (lookupKeyWrite(c
->db
,key
) != NULL
&& nx
) {
30 addReply(c
,shared
.czero
);
33 setKey(c
->db
,key
,val
);
35 if (expire
) setExpire(c
->db
,key
,mstime()+milliseconds
);
36 addReply(c
, nx
? shared
.cone
: shared
.ok
);
39 void setCommand(redisClient
*c
) {
40 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
41 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[2],NULL
,0);
44 void setnxCommand(redisClient
*c
) {
45 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
46 setGenericCommand(c
,1,c
->argv
[1],c
->argv
[2],NULL
,0);
49 void setexCommand(redisClient
*c
) {
50 c
->argv
[3] = tryObjectEncoding(c
->argv
[3]);
51 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[3],c
->argv
[2],UNIT_SECONDS
);
54 void psetexCommand(redisClient
*c
) {
55 c
->argv
[3] = tryObjectEncoding(c
->argv
[3]);
56 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[3],c
->argv
[2],UNIT_MILLISECONDS
);
59 int getGenericCommand(redisClient
*c
) {
62 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
)
65 if (o
->type
!= REDIS_STRING
) {
66 addReply(c
,shared
.wrongtypeerr
);
74 void getCommand(redisClient
*c
) {
78 void getsetCommand(redisClient
*c
) {
79 if (getGenericCommand(c
) == REDIS_ERR
) return;
80 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
81 setKey(c
->db
,c
->argv
[1],c
->argv
[2]);
85 static int getBitOffsetFromArgument(redisClient
*c
, robj
*o
, size_t *offset
) {
87 char *err
= "bit offset is not an integer or out of range";
89 if (getLongLongFromObjectOrReply(c
,o
,&loffset
,err
) != REDIS_OK
)
92 /* Limit offset to 512MB in bytes */
93 if ((loffset
< 0) || ((unsigned long long)loffset
>> 3) >= (512*1024*1024))
99 *offset
= (size_t)loffset
;
103 void setbitCommand(redisClient
*c
) {
105 char *err
= "bit is not an integer or out of range";
111 if (getBitOffsetFromArgument(c
,c
->argv
[2],&bitoffset
) != REDIS_OK
)
114 if (getLongFromObjectOrReply(c
,c
->argv
[3],&on
,err
) != REDIS_OK
)
117 /* Bits can only be set or cleared... */
119 addReplyError(c
,err
);
123 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
125 o
= createObject(REDIS_STRING
,sdsempty());
126 dbAdd(c
->db
,c
->argv
[1],o
);
128 if (checkType(c
,o
,REDIS_STRING
)) return;
130 /* Create a copy when the object is shared or encoded. */
131 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
132 robj
*decoded
= getDecodedObject(o
);
133 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
134 decrRefCount(decoded
);
135 dbOverwrite(c
->db
,c
->argv
[1],o
);
139 /* Grow sds value to the right length if necessary */
140 byte
= bitoffset
>> 3;
141 o
->ptr
= sdsgrowzero(o
->ptr
,byte
+1);
143 /* Get current values */
144 byteval
= ((char*)o
->ptr
)[byte
];
145 bit
= 7 - (bitoffset
& 0x7);
146 bitval
= byteval
& (1 << bit
);
148 /* Update byte with new bit value and return original value */
149 byteval
&= ~(1 << bit
);
150 byteval
|= ((on
& 0x1) << bit
);
151 ((char*)o
->ptr
)[byte
] = byteval
;
152 signalModifiedKey(c
->db
,c
->argv
[1]);
154 addReply(c
, bitval
? shared
.cone
: shared
.czero
);
157 void getbitCommand(redisClient
*c
) {
164 if (getBitOffsetFromArgument(c
,c
->argv
[2],&bitoffset
) != REDIS_OK
)
167 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
168 checkType(c
,o
,REDIS_STRING
)) return;
170 byte
= bitoffset
>> 3;
171 bit
= 7 - (bitoffset
& 0x7);
172 if (o
->encoding
!= REDIS_ENCODING_RAW
) {
173 if (byte
< (size_t)ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
))
174 bitval
= llbuf
[byte
] & (1 << bit
);
176 if (byte
< sdslen(o
->ptr
))
177 bitval
= ((char*)o
->ptr
)[byte
] & (1 << bit
);
180 addReply(c
, bitval
? shared
.cone
: shared
.czero
);
183 void setrangeCommand(redisClient
*c
) {
186 sds value
= c
->argv
[3]->ptr
;
188 if (getLongFromObjectOrReply(c
,c
->argv
[2],&offset
,NULL
) != REDIS_OK
)
192 addReplyError(c
,"offset is out of range");
196 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
198 /* Return 0 when setting nothing on a non-existing string */
199 if (sdslen(value
) == 0) {
200 addReply(c
,shared
.czero
);
204 /* Return when the resulting string exceeds allowed size */
205 if (checkStringLength(c
,offset
+sdslen(value
)) != REDIS_OK
)
208 o
= createObject(REDIS_STRING
,sdsempty());
209 dbAdd(c
->db
,c
->argv
[1],o
);
213 /* Key exists, check type */
214 if (checkType(c
,o
,REDIS_STRING
))
217 /* Return existing string length when setting nothing */
218 olen
= stringObjectLen(o
);
219 if (sdslen(value
) == 0) {
220 addReplyLongLong(c
,olen
);
224 /* Return when the resulting string exceeds allowed size */
225 if (checkStringLength(c
,offset
+sdslen(value
)) != REDIS_OK
)
228 /* Create a copy when the object is shared or encoded. */
229 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
230 robj
*decoded
= getDecodedObject(o
);
231 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
232 decrRefCount(decoded
);
233 dbOverwrite(c
->db
,c
->argv
[1],o
);
237 if (sdslen(value
) > 0) {
238 o
->ptr
= sdsgrowzero(o
->ptr
,offset
+sdslen(value
));
239 memcpy((char*)o
->ptr
+offset
,value
,sdslen(value
));
240 signalModifiedKey(c
->db
,c
->argv
[1]);
243 addReplyLongLong(c
,sdslen(o
->ptr
));
246 void getrangeCommand(redisClient
*c
) {
249 char *str
, llbuf
[32];
252 if (getLongFromObjectOrReply(c
,c
->argv
[2],&start
,NULL
) != REDIS_OK
)
254 if (getLongFromObjectOrReply(c
,c
->argv
[3],&end
,NULL
) != REDIS_OK
)
256 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.emptybulk
)) == NULL
||
257 checkType(c
,o
,REDIS_STRING
)) return;
259 if (o
->encoding
== REDIS_ENCODING_INT
) {
261 strlen
= ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
);
264 strlen
= sdslen(str
);
267 /* Convert negative indexes */
268 if (start
< 0) start
= strlen
+start
;
269 if (end
< 0) end
= strlen
+end
;
270 if (start
< 0) start
= 0;
271 if (end
< 0) end
= 0;
272 if ((unsigned)end
>= strlen
) end
= strlen
-1;
274 /* Precondition: end >= 0 && end < strlen, so the only condition where
275 * nothing can be returned is: start > end. */
277 addReply(c
,shared
.emptybulk
);
279 addReplyBulkCBuffer(c
,(char*)str
+start
,end
-start
+1);
283 void mgetCommand(redisClient
*c
) {
286 addReplyMultiBulkLen(c
,c
->argc
-1);
287 for (j
= 1; j
< c
->argc
; j
++) {
288 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
290 addReply(c
,shared
.nullbulk
);
292 if (o
->type
!= REDIS_STRING
) {
293 addReply(c
,shared
.nullbulk
);
301 void msetGenericCommand(redisClient
*c
, int nx
) {
304 if ((c
->argc
% 2) == 0) {
305 addReplyError(c
,"wrong number of arguments for MSET");
308 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
309 * set nothing at all if at least one already key exists. */
311 for (j
= 1; j
< c
->argc
; j
+= 2) {
312 if (lookupKeyWrite(c
->db
,c
->argv
[j
]) != NULL
) {
317 addReply(c
, shared
.czero
);
322 for (j
= 1; j
< c
->argc
; j
+= 2) {
323 c
->argv
[j
+1] = tryObjectEncoding(c
->argv
[j
+1]);
324 setKey(c
->db
,c
->argv
[j
],c
->argv
[j
+1]);
326 server
.dirty
+= (c
->argc
-1)/2;
327 addReply(c
, nx
? shared
.cone
: shared
.ok
);
330 void msetCommand(redisClient
*c
) {
331 msetGenericCommand(c
,0);
334 void msetnxCommand(redisClient
*c
) {
335 msetGenericCommand(c
,1);
338 void incrDecrCommand(redisClient
*c
, long long incr
) {
339 long long value
, oldvalue
;
342 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
343 if (o
!= NULL
&& checkType(c
,o
,REDIS_STRING
)) return;
344 if (getLongLongFromObjectOrReply(c
,o
,&value
,NULL
) != REDIS_OK
) return;
347 if ((incr
< 0 && oldvalue
< 0 && incr
< (LLONG_MIN
-oldvalue
)) ||
348 (incr
> 0 && oldvalue
> 0 && incr
> (LLONG_MAX
-oldvalue
))) {
349 addReplyError(c
,"increment or decrement would overflow");
353 new = createStringObjectFromLongLong(value
);
355 dbOverwrite(c
->db
,c
->argv
[1],new);
357 dbAdd(c
->db
,c
->argv
[1],new);
358 signalModifiedKey(c
->db
,c
->argv
[1]);
360 addReply(c
,shared
.colon
);
362 addReply(c
,shared
.crlf
);
365 void incrCommand(redisClient
*c
) {
366 incrDecrCommand(c
,1);
369 void decrCommand(redisClient
*c
) {
370 incrDecrCommand(c
,-1);
373 void incrbyCommand(redisClient
*c
) {
376 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
377 incrDecrCommand(c
,incr
);
380 void decrbyCommand(redisClient
*c
) {
383 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
384 incrDecrCommand(c
,-incr
);
387 void incrbyfloatCommand(redisClient
*c
) {
388 long double incr
, value
;
391 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
392 if (o
!= NULL
&& checkType(c
,o
,REDIS_STRING
)) return;
393 if (getLongDoubleFromObjectOrReply(c
,o
,&value
,NULL
) != REDIS_OK
||
394 getLongDoubleFromObjectOrReply(c
,c
->argv
[2],&incr
,NULL
) != REDIS_OK
)
398 if (isnan(value
) || isinf(value
)) {
399 addReplyError(c
,"increment would produce NaN or Infinity");
402 new = createStringObjectFromLongDouble(value
);
404 dbOverwrite(c
->db
,c
->argv
[1],new);
406 dbAdd(c
->db
,c
->argv
[1],new);
407 signalModifiedKey(c
->db
,c
->argv
[1]);
411 /* Always replicate INCRBYFLOAT as a SET command with the final value
412 * in order to make sure that differences in float pricision or formatting
413 * will not create differences in replicas or after an AOF restart. */
414 aux
= createStringObject("SET",3);
415 rewriteClientCommandArgument(c
,0,aux
);
417 rewriteClientCommandArgument(c
,2,new);
420 void appendCommand(redisClient
*c
) {
424 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
427 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
428 dbAdd(c
->db
,c
->argv
[1],c
->argv
[2]);
429 incrRefCount(c
->argv
[2]);
430 totlen
= stringObjectLen(c
->argv
[2]);
432 /* Key exists, check type */
433 if (checkType(c
,o
,REDIS_STRING
))
436 /* "append" is an argument, so always an sds */
438 totlen
= stringObjectLen(o
)+sdslen(append
->ptr
);
439 if (checkStringLength(c
,totlen
) != REDIS_OK
)
442 /* If the object is shared or encoded, we have to make a copy */
443 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
444 robj
*decoded
= getDecodedObject(o
);
445 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
446 decrRefCount(decoded
);
447 dbOverwrite(c
->db
,c
->argv
[1],o
);
450 /* Append the value */
451 o
->ptr
= sdscatlen(o
->ptr
,append
->ptr
,sdslen(append
->ptr
));
452 totlen
= sdslen(o
->ptr
);
454 signalModifiedKey(c
->db
,c
->argv
[1]);
456 addReplyLongLong(c
,totlen
);
459 void strlenCommand(redisClient
*c
) {
461 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
462 checkType(c
,o
,REDIS_STRING
)) return;
463 addReplyLongLong(c
,stringObjectLen(o
));