]>
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
) {
16 long seconds
= 0; /* initialized to avoid an harmness warning */
19 if (getLongFromObjectOrReply(c
, expire
, &seconds
, NULL
) != REDIS_OK
)
22 addReplyError(c
,"invalid expire time in SETEX");
27 if (lookupKeyWrite(c
->db
,key
) != NULL
&& nx
) {
28 addReply(c
,shared
.czero
);
31 setKey(c
->db
,key
,val
);
33 if (expire
) setExpire(c
->db
,key
,time(NULL
)+seconds
);
34 addReply(c
, nx
? shared
.cone
: shared
.ok
);
37 void setCommand(redisClient
*c
) {
38 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
39 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[2],NULL
);
42 void setnxCommand(redisClient
*c
) {
43 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
44 setGenericCommand(c
,1,c
->argv
[1],c
->argv
[2],NULL
);
47 void setexCommand(redisClient
*c
) {
48 c
->argv
[3] = tryObjectEncoding(c
->argv
[3]);
49 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[3],c
->argv
[2]);
52 int getGenericCommand(redisClient
*c
) {
55 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
)
58 if (o
->type
!= REDIS_STRING
) {
59 addReply(c
,shared
.wrongtypeerr
);
67 void getCommand(redisClient
*c
) {
71 void getsetCommand(redisClient
*c
) {
72 if (getGenericCommand(c
) == REDIS_ERR
) return;
73 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
74 setKey(c
->db
,c
->argv
[1],c
->argv
[2]);
76 removeExpire(c
->db
,c
->argv
[1]);
79 static int getBitOffsetFromArgument(redisClient
*c
, robj
*o
, size_t *offset
) {
81 char *err
= "bit offset is not an integer or out of range";
83 if (getLongLongFromObjectOrReply(c
,o
,&loffset
,err
) != REDIS_OK
)
86 /* Limit offset to 512MB in bytes */
87 if ((loffset
< 0) || ((unsigned long long)loffset
>> 3) >= (512*1024*1024))
93 *offset
= (size_t)loffset
;
97 void setbitCommand(redisClient
*c
) {
99 char *err
= "bit is not an integer or out of range";
105 if (getBitOffsetFromArgument(c
,c
->argv
[2],&bitoffset
) != REDIS_OK
)
108 if (getLongFromObjectOrReply(c
,c
->argv
[3],&on
,err
) != REDIS_OK
)
111 /* Bits can only be set or cleared... */
113 addReplyError(c
,err
);
117 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
119 o
= createObject(REDIS_STRING
,sdsempty());
120 dbAdd(c
->db
,c
->argv
[1],o
);
122 if (checkType(c
,o
,REDIS_STRING
)) return;
124 /* Create a copy when the object is shared or encoded. */
125 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
126 robj
*decoded
= getDecodedObject(o
);
127 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
128 decrRefCount(decoded
);
129 dbOverwrite(c
->db
,c
->argv
[1],o
);
133 /* Grow sds value to the right length if necessary */
134 byte
= bitoffset
>> 3;
135 o
->ptr
= sdsgrowzero(o
->ptr
,byte
+1);
137 /* Get current values */
138 byteval
= ((char*)o
->ptr
)[byte
];
139 bit
= 7 - (bitoffset
& 0x7);
140 bitval
= byteval
& (1 << bit
);
142 /* Update byte with new bit value and return original value */
143 byteval
&= ~(1 << bit
);
144 byteval
|= ((on
& 0x1) << bit
);
145 ((char*)o
->ptr
)[byte
] = byteval
;
146 signalModifiedKey(c
->db
,c
->argv
[1]);
148 addReply(c
, bitval
? shared
.cone
: shared
.czero
);
151 void getbitCommand(redisClient
*c
) {
158 if (getBitOffsetFromArgument(c
,c
->argv
[2],&bitoffset
) != REDIS_OK
)
161 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
162 checkType(c
,o
,REDIS_STRING
)) return;
164 byte
= bitoffset
>> 3;
165 bit
= 7 - (bitoffset
& 0x7);
166 if (o
->encoding
!= REDIS_ENCODING_RAW
) {
167 if (byte
< (size_t)ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
))
168 bitval
= llbuf
[byte
] & (1 << bit
);
170 if (byte
< sdslen(o
->ptr
))
171 bitval
= ((char*)o
->ptr
)[byte
] & (1 << bit
);
174 addReply(c
, bitval
? shared
.cone
: shared
.czero
);
177 void setrangeCommand(redisClient
*c
) {
180 sds value
= c
->argv
[3]->ptr
;
182 if (getLongFromObjectOrReply(c
,c
->argv
[2],&offset
,NULL
) != REDIS_OK
)
186 addReplyError(c
,"offset is out of range");
190 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
192 /* Return 0 when setting nothing on a non-existing string */
193 if (sdslen(value
) == 0) {
194 addReply(c
,shared
.czero
);
198 /* Return when the resulting string exceeds allowed size */
199 if (checkStringLength(c
,offset
+sdslen(value
)) != REDIS_OK
)
202 o
= createObject(REDIS_STRING
,sdsempty());
203 dbAdd(c
->db
,c
->argv
[1],o
);
207 /* Key exists, check type */
208 if (checkType(c
,o
,REDIS_STRING
))
211 /* Return existing string length when setting nothing */
212 olen
= stringObjectLen(o
);
213 if (sdslen(value
) == 0) {
214 addReplyLongLong(c
,olen
);
218 /* Return when the resulting string exceeds allowed size */
219 if (checkStringLength(c
,offset
+sdslen(value
)) != REDIS_OK
)
222 /* Create a copy when the object is shared or encoded. */
223 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
224 robj
*decoded
= getDecodedObject(o
);
225 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
226 decrRefCount(decoded
);
227 dbOverwrite(c
->db
,c
->argv
[1],o
);
231 if (sdslen(value
) > 0) {
232 o
->ptr
= sdsgrowzero(o
->ptr
,offset
+sdslen(value
));
233 memcpy((char*)o
->ptr
+offset
,value
,sdslen(value
));
234 signalModifiedKey(c
->db
,c
->argv
[1]);
237 addReplyLongLong(c
,sdslen(o
->ptr
));
240 void getrangeCommand(redisClient
*c
) {
243 char *str
, llbuf
[32];
246 if (getLongFromObjectOrReply(c
,c
->argv
[2],&start
,NULL
) != REDIS_OK
)
248 if (getLongFromObjectOrReply(c
,c
->argv
[3],&end
,NULL
) != REDIS_OK
)
250 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.emptybulk
)) == NULL
||
251 checkType(c
,o
,REDIS_STRING
)) return;
253 if (o
->encoding
== REDIS_ENCODING_INT
) {
255 strlen
= ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
);
258 strlen
= sdslen(str
);
261 /* Convert negative indexes */
262 if (start
< 0) start
= strlen
+start
;
263 if (end
< 0) end
= strlen
+end
;
264 if (start
< 0) start
= 0;
265 if (end
< 0) end
= 0;
266 if ((unsigned)end
>= strlen
) end
= strlen
-1;
268 /* Precondition: end >= 0 && end < strlen, so the only condition where
269 * nothing can be returned is: start > end. */
271 addReply(c
,shared
.emptybulk
);
273 addReplyBulkCBuffer(c
,(char*)str
+start
,end
-start
+1);
277 void mgetCommand(redisClient
*c
) {
280 addReplyMultiBulkLen(c
,c
->argc
-1);
281 for (j
= 1; j
< c
->argc
; j
++) {
282 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
284 addReply(c
,shared
.nullbulk
);
286 if (o
->type
!= REDIS_STRING
) {
287 addReply(c
,shared
.nullbulk
);
295 void msetGenericCommand(redisClient
*c
, int nx
) {
298 if ((c
->argc
% 2) == 0) {
299 addReplyError(c
,"wrong number of arguments for MSET");
302 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
303 * set nothing at all if at least one already key exists. */
305 for (j
= 1; j
< c
->argc
; j
+= 2) {
306 if (lookupKeyWrite(c
->db
,c
->argv
[j
]) != NULL
) {
311 addReply(c
, shared
.czero
);
316 for (j
= 1; j
< c
->argc
; j
+= 2) {
317 c
->argv
[j
+1] = tryObjectEncoding(c
->argv
[j
+1]);
318 setKey(c
->db
,c
->argv
[j
],c
->argv
[j
+1]);
320 server
.dirty
+= (c
->argc
-1)/2;
321 addReply(c
, nx
? shared
.cone
: shared
.ok
);
324 void msetCommand(redisClient
*c
) {
325 msetGenericCommand(c
,0);
328 void msetnxCommand(redisClient
*c
) {
329 msetGenericCommand(c
,1);
332 void incrDecrCommand(redisClient
*c
, long long incr
) {
333 long long value
, oldvalue
;
336 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
337 if (o
!= NULL
&& checkType(c
,o
,REDIS_STRING
)) return;
338 if (getLongLongFromObjectOrReply(c
,o
,&value
,NULL
) != REDIS_OK
) return;
342 if ((incr
< 0 && value
> oldvalue
) || (incr
> 0 && value
< oldvalue
)) {
343 addReplyError(c
,"increment or decrement would overflow");
346 new = createStringObjectFromLongLong(value
);
348 dbOverwrite(c
->db
,c
->argv
[1],new);
350 dbAdd(c
->db
,c
->argv
[1],new);
351 signalModifiedKey(c
->db
,c
->argv
[1]);
353 addReply(c
,shared
.colon
);
355 addReply(c
,shared
.crlf
);
358 void incrCommand(redisClient
*c
) {
359 incrDecrCommand(c
,1);
362 void decrCommand(redisClient
*c
) {
363 incrDecrCommand(c
,-1);
366 void incrbyCommand(redisClient
*c
) {
369 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
370 incrDecrCommand(c
,incr
);
373 void decrbyCommand(redisClient
*c
) {
376 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
377 incrDecrCommand(c
,-incr
);
380 void appendCommand(redisClient
*c
) {
384 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
387 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
388 dbAdd(c
->db
,c
->argv
[1],c
->argv
[2]);
389 incrRefCount(c
->argv
[2]);
390 totlen
= stringObjectLen(c
->argv
[2]);
392 /* Key exists, check type */
393 if (checkType(c
,o
,REDIS_STRING
))
396 /* "append" is an argument, so always an sds */
398 totlen
= stringObjectLen(o
)+sdslen(append
->ptr
);
399 if (checkStringLength(c
,totlen
) != REDIS_OK
)
402 /* If the object is shared or encoded, we have to make a copy */
403 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
404 robj
*decoded
= getDecodedObject(o
);
405 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
406 decrRefCount(decoded
);
407 dbOverwrite(c
->db
,c
->argv
[1],o
);
410 /* Append the value */
411 o
->ptr
= sdscatlen(o
->ptr
,append
->ptr
,sdslen(append
->ptr
));
412 totlen
= sdslen(o
->ptr
);
414 signalModifiedKey(c
->db
,c
->argv
[1]);
416 addReplyLongLong(c
,totlen
);
419 void strlenCommand(redisClient
*c
) {
421 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
422 checkType(c
,o
,REDIS_STRING
)) return;
423 addReplyLongLong(c
,stringObjectLen(o
));