]>
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
) {
17 long seconds
= 0; /* initialized to avoid an harmness warning */
20 if (getLongFromObjectOrReply(c
, expire
, &seconds
, NULL
) != REDIS_OK
)
23 addReplyError(c
,"invalid expire time in SETEX");
28 retval
= dbAdd(c
->db
,key
,val
);
29 if (retval
== REDIS_ERR
) {
31 dbReplace(c
->db
,key
,val
);
34 addReply(c
,shared
.czero
);
40 signalModifiedKey(c
->db
,key
);
42 removeExpire(c
->db
,key
);
43 if (expire
) setExpire(c
->db
,key
,time(NULL
)+seconds
);
44 addReply(c
, nx
? shared
.cone
: shared
.ok
);
47 void setCommand(redisClient
*c
) {
48 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
49 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[2],NULL
);
52 void setnxCommand(redisClient
*c
) {
53 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
54 setGenericCommand(c
,1,c
->argv
[1],c
->argv
[2],NULL
);
57 void setexCommand(redisClient
*c
) {
58 c
->argv
[3] = tryObjectEncoding(c
->argv
[3]);
59 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[3],c
->argv
[2]);
62 int getGenericCommand(redisClient
*c
) {
65 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
)
68 if (o
->type
!= REDIS_STRING
) {
69 addReply(c
,shared
.wrongtypeerr
);
77 void getCommand(redisClient
*c
) {
81 void getsetCommand(redisClient
*c
) {
82 if (getGenericCommand(c
) == REDIS_ERR
) return;
83 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
84 dbReplace(c
->db
,c
->argv
[1],c
->argv
[2]);
85 incrRefCount(c
->argv
[2]);
86 signalModifiedKey(c
->db
,c
->argv
[1]);
88 removeExpire(c
->db
,c
->argv
[1]);
91 static int getBitOffsetFromArgument(redisClient
*c
, robj
*o
, size_t *offset
) {
93 char *err
= "bit offset is not an integer or out of range";
95 if (getLongLongFromObjectOrReply(c
,o
,&loffset
,err
) != REDIS_OK
)
98 /* Limit offset to 512MB in bytes */
99 if ((loffset
< 0) || ((unsigned long long)loffset
>> 3) >= (512*1024*1024))
101 addReplyError(c
,err
);
105 *offset
= (size_t)loffset
;
109 void setbitCommand(redisClient
*c
) {
111 char *err
= "bit is not an integer or out of range";
117 if (getBitOffsetFromArgument(c
,c
->argv
[2],&bitoffset
) != REDIS_OK
)
120 if (getLongFromObjectOrReply(c
,c
->argv
[3],&on
,err
) != REDIS_OK
)
123 /* Bits can only be set or cleared... */
125 addReplyError(c
,err
);
129 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
131 o
= createObject(REDIS_STRING
,sdsempty());
132 dbAdd(c
->db
,c
->argv
[1],o
);
134 if (checkType(c
,o
,REDIS_STRING
)) return;
136 /* Create a copy when the object is shared or encoded. */
137 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
138 robj
*decoded
= getDecodedObject(o
);
139 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
140 decrRefCount(decoded
);
141 dbReplace(c
->db
,c
->argv
[1],o
);
145 /* Grow sds value to the right length if necessary */
146 byte
= bitoffset
>> 3;
147 o
->ptr
= sdsgrowzero(o
->ptr
,byte
+1);
149 /* Get current values */
150 byteval
= ((char*)o
->ptr
)[byte
];
151 bit
= 7 - (bitoffset
& 0x7);
152 bitval
= byteval
& (1 << bit
);
154 /* Update byte with new bit value and return original value */
155 byteval
&= ~(1 << bit
);
156 byteval
|= ((on
& 0x1) << bit
);
157 ((char*)o
->ptr
)[byte
] = byteval
;
158 signalModifiedKey(c
->db
,c
->argv
[1]);
160 addReply(c
, bitval
? shared
.cone
: shared
.czero
);
163 void getbitCommand(redisClient
*c
) {
170 if (getBitOffsetFromArgument(c
,c
->argv
[2],&bitoffset
) != REDIS_OK
)
173 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
174 checkType(c
,o
,REDIS_STRING
)) return;
176 byte
= bitoffset
>> 3;
177 bit
= 7 - (bitoffset
& 0x7);
178 if (o
->encoding
!= REDIS_ENCODING_RAW
) {
179 if (byte
< (size_t)ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
))
180 bitval
= llbuf
[byte
] & (1 << bit
);
182 if (byte
< sdslen(o
->ptr
))
183 bitval
= ((char*)o
->ptr
)[byte
] & (1 << bit
);
186 addReply(c
, bitval
? shared
.cone
: shared
.czero
);
189 void setrangeCommand(redisClient
*c
) {
192 sds value
= c
->argv
[3]->ptr
;
194 if (getLongFromObjectOrReply(c
,c
->argv
[2],&offset
,NULL
) != REDIS_OK
)
198 addReplyError(c
,"offset is out of range");
202 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
204 /* Return 0 when setting nothing on a non-existing string */
205 if (sdslen(value
) == 0) {
206 addReply(c
,shared
.czero
);
210 /* Return when the resulting string exceeds allowed size */
211 if (checkStringLength(c
,offset
+sdslen(value
)) != REDIS_OK
)
214 o
= createObject(REDIS_STRING
,sdsempty());
215 dbAdd(c
->db
,c
->argv
[1],o
);
219 /* Key exists, check type */
220 if (checkType(c
,o
,REDIS_STRING
))
223 /* Return existing string length when setting nothing */
224 olen
= stringObjectLen(o
);
225 if (sdslen(value
) == 0) {
226 addReplyLongLong(c
,olen
);
230 /* Return when the resulting string exceeds allowed size */
231 if (checkStringLength(c
,offset
+sdslen(value
)) != REDIS_OK
)
234 /* Create a copy when the object is shared or encoded. */
235 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
236 robj
*decoded
= getDecodedObject(o
);
237 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
238 decrRefCount(decoded
);
239 dbReplace(c
->db
,c
->argv
[1],o
);
243 if (sdslen(value
) > 0) {
244 o
->ptr
= sdsgrowzero(o
->ptr
,offset
+sdslen(value
));
245 memcpy((char*)o
->ptr
+offset
,value
,sdslen(value
));
246 signalModifiedKey(c
->db
,c
->argv
[1]);
249 addReplyLongLong(c
,sdslen(o
->ptr
));
252 void getrangeCommand(redisClient
*c
) {
255 char *str
, llbuf
[32];
258 if (getLongFromObjectOrReply(c
,c
->argv
[2],&start
,NULL
) != REDIS_OK
)
260 if (getLongFromObjectOrReply(c
,c
->argv
[3],&end
,NULL
) != REDIS_OK
)
262 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
263 checkType(c
,o
,REDIS_STRING
)) return;
265 if (o
->encoding
== REDIS_ENCODING_INT
) {
267 strlen
= ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
);
270 strlen
= sdslen(str
);
273 /* Convert negative indexes */
274 if (start
< 0) start
= strlen
+start
;
275 if (end
< 0) end
= strlen
+end
;
276 if (start
< 0) start
= 0;
277 if (end
< 0) end
= 0;
278 if ((unsigned)end
>= strlen
) end
= strlen
-1;
280 /* Precondition: end >= 0 && end < strlen, so the only condition where
281 * nothing can be returned is: start > end. */
283 addReply(c
,shared
.nullbulk
);
285 addReplyBulkCBuffer(c
,(char*)str
+start
,end
-start
+1);
289 void mgetCommand(redisClient
*c
) {
292 addReplyMultiBulkLen(c
,c
->argc
-1);
293 for (j
= 1; j
< c
->argc
; j
++) {
294 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
296 addReply(c
,shared
.nullbulk
);
298 if (o
->type
!= REDIS_STRING
) {
299 addReply(c
,shared
.nullbulk
);
307 void msetGenericCommand(redisClient
*c
, int nx
) {
310 if ((c
->argc
% 2) == 0) {
311 addReplyError(c
,"wrong number of arguments for MSET");
314 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
315 * set nothing at all if at least one already key exists. */
317 for (j
= 1; j
< c
->argc
; j
+= 2) {
318 if (lookupKeyWrite(c
->db
,c
->argv
[j
]) != NULL
) {
324 addReply(c
, shared
.czero
);
328 for (j
= 1; j
< c
->argc
; j
+= 2) {
329 c
->argv
[j
+1] = tryObjectEncoding(c
->argv
[j
+1]);
330 dbReplace(c
->db
,c
->argv
[j
],c
->argv
[j
+1]);
331 incrRefCount(c
->argv
[j
+1]);
332 removeExpire(c
->db
,c
->argv
[j
]);
333 signalModifiedKey(c
->db
,c
->argv
[j
]);
335 server
.dirty
+= (c
->argc
-1)/2;
336 addReply(c
, nx
? shared
.cone
: shared
.ok
);
339 void msetCommand(redisClient
*c
) {
340 msetGenericCommand(c
,0);
343 void msetnxCommand(redisClient
*c
) {
344 msetGenericCommand(c
,1);
347 void incrDecrCommand(redisClient
*c
, long long incr
) {
348 long long value
, oldvalue
;
351 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
352 if (o
!= NULL
&& checkType(c
,o
,REDIS_STRING
)) return;
353 if (getLongLongFromObjectOrReply(c
,o
,&value
,NULL
) != REDIS_OK
) return;
357 if ((incr
< 0 && value
> oldvalue
) || (incr
> 0 && value
< oldvalue
)) {
358 addReplyError(c
,"increment or decrement would overflow");
361 o
= createStringObjectFromLongLong(value
);
362 dbReplace(c
->db
,c
->argv
[1],o
);
363 signalModifiedKey(c
->db
,c
->argv
[1]);
365 addReply(c
,shared
.colon
);
367 addReply(c
,shared
.crlf
);
370 void incrCommand(redisClient
*c
) {
371 incrDecrCommand(c
,1);
374 void decrCommand(redisClient
*c
) {
375 incrDecrCommand(c
,-1);
378 void incrbyCommand(redisClient
*c
) {
381 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
382 incrDecrCommand(c
,incr
);
385 void decrbyCommand(redisClient
*c
) {
388 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
389 incrDecrCommand(c
,-incr
);
392 void appendCommand(redisClient
*c
) {
396 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
399 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
400 dbAdd(c
->db
,c
->argv
[1],c
->argv
[2]);
401 incrRefCount(c
->argv
[2]);
402 totlen
= stringObjectLen(c
->argv
[2]);
404 /* Key exists, check type */
405 if (checkType(c
,o
,REDIS_STRING
))
408 /* "append" is an argument, so always an sds */
410 totlen
= stringObjectLen(o
)+sdslen(append
->ptr
);
411 if (checkStringLength(c
,totlen
) != REDIS_OK
)
414 /* If the object is shared or encoded, we have to make a copy */
415 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
416 robj
*decoded
= getDecodedObject(o
);
417 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
418 decrRefCount(decoded
);
419 dbReplace(c
->db
,c
->argv
[1],o
);
422 /* Append the value */
423 o
->ptr
= sdscatlen(o
->ptr
,append
->ptr
,sdslen(append
->ptr
));
424 totlen
= sdslen(o
->ptr
);
426 signalModifiedKey(c
->db
,c
->argv
[1]);
428 addReplyLongLong(c
,totlen
);
431 void strlenCommand(redisClient
*c
) {
433 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
434 checkType(c
,o
,REDIS_STRING
)) return;
435 addReplyLongLong(c
,stringObjectLen(o
));