]>
git.saurik.com Git - redis.git/blob - src/t_string.c
d537c8b909fe20942dfa615c18fcf26549157638
4 /*-----------------------------------------------------------------------------
6 *----------------------------------------------------------------------------*/
8 void setGenericCommand(redisClient
*c
, int nx
, robj
*key
, robj
*val
, robj
*expire
) {
10 long seconds
= 0; /* initialized to avoid an harmness warning */
13 if (getLongFromObjectOrReply(c
, expire
, &seconds
, NULL
) != REDIS_OK
)
16 addReplyError(c
,"invalid expire time in SETEX");
21 retval
= dbAdd(c
->db
,key
,val
);
22 if (retval
== REDIS_ERR
) {
24 dbReplace(c
->db
,key
,val
);
27 addReply(c
,shared
.czero
);
33 touchWatchedKey(c
->db
,key
);
35 removeExpire(c
->db
,key
);
36 if (expire
) setExpire(c
->db
,key
,time(NULL
)+seconds
);
37 addReply(c
, nx
? shared
.cone
: shared
.ok
);
40 void setCommand(redisClient
*c
) {
41 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
42 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[2],NULL
);
45 void setnxCommand(redisClient
*c
) {
46 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
47 setGenericCommand(c
,1,c
->argv
[1],c
->argv
[2],NULL
);
50 void setexCommand(redisClient
*c
) {
51 c
->argv
[3] = tryObjectEncoding(c
->argv
[3]);
52 setGenericCommand(c
,0,c
->argv
[1],c
->argv
[3],c
->argv
[2]);
55 int getGenericCommand(redisClient
*c
) {
58 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
)
61 if (o
->type
!= REDIS_STRING
) {
62 addReply(c
,shared
.wrongtypeerr
);
70 void getCommand(redisClient
*c
) {
74 void getsetCommand(redisClient
*c
) {
75 if (getGenericCommand(c
) == REDIS_ERR
) return;
76 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
77 dbReplace(c
->db
,c
->argv
[1],c
->argv
[2]);
78 incrRefCount(c
->argv
[2]);
79 touchWatchedKey(c
->db
,c
->argv
[1]);
81 removeExpire(c
->db
,c
->argv
[1]);
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 SIZE_T_MAX or 512MB in bytes */
93 ((unsigned long long)loffset
>= (unsigned)SIZE_T_MAX
) ||
94 ((unsigned long long)loffset
>> 3) >= (512*1024*1024))
100 *offset
= (size_t)loffset
;
104 void setbitCommand(redisClient
*c
) {
106 char *err
= "bit is not an integer or out of range";
111 if (getBitOffsetFromArgument(c
,c
->argv
[2],&bitoffset
) != REDIS_OK
)
114 if (getLongLongFromObjectOrReply(c
,c
->argv
[3],&bitvalue
,err
) != REDIS_OK
)
117 /* A bit can only be set to be on or off... */
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 dbReplace(c
->db
,c
->argv
[1],o
);
139 byte
= bitoffset
>> 3;
140 bit
= 7 - (bitoffset
& 0x7);
142 o
->ptr
= sdsgrowzero(o
->ptr
,byte
+1);
143 ((char*)o
->ptr
)[byte
] |= on
<< bit
;
144 ((char*)o
->ptr
)[byte
] &= ~((!on
) << bit
);
146 touchWatchedKey(c
->db
,c
->argv
[1]);
148 addReply(c
,shared
.cone
);
151 void getbitCommand(redisClient
*c
) {
153 size_t bitoffset
, byte
, bitmask
;
157 if (getBitOffsetFromArgument(c
,c
->argv
[2],&bitoffset
) != REDIS_OK
)
160 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
161 checkType(c
,o
,REDIS_STRING
)) return;
163 byte
= bitoffset
>> 3;
164 bitmask
= 1 << (7 - (bitoffset
& 0x7));
165 if (o
->encoding
!= REDIS_ENCODING_RAW
) {
166 if (byte
< (size_t)ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
))
167 on
= llbuf
[byte
] & bitmask
;
169 if (byte
< sdslen(o
->ptr
))
170 on
= ((sds
)o
->ptr
)[byte
] & bitmask
;
172 addReply(c
, on
? shared
.cone
: shared
.czero
);
175 void mgetCommand(redisClient
*c
) {
178 addReplyMultiBulkLen(c
,c
->argc
-1);
179 for (j
= 1; j
< c
->argc
; j
++) {
180 robj
*o
= lookupKeyRead(c
->db
,c
->argv
[j
]);
182 addReply(c
,shared
.nullbulk
);
184 if (o
->type
!= REDIS_STRING
) {
185 addReply(c
,shared
.nullbulk
);
193 void msetGenericCommand(redisClient
*c
, int nx
) {
196 if ((c
->argc
% 2) == 0) {
197 addReplyError(c
,"wrong number of arguments for MSET");
200 /* Handle the NX flag. The MSETNX semantic is to return zero and don't
201 * set nothing at all if at least one already key exists. */
203 for (j
= 1; j
< c
->argc
; j
+= 2) {
204 if (lookupKeyWrite(c
->db
,c
->argv
[j
]) != NULL
) {
210 addReply(c
, shared
.czero
);
214 for (j
= 1; j
< c
->argc
; j
+= 2) {
215 c
->argv
[j
+1] = tryObjectEncoding(c
->argv
[j
+1]);
216 dbReplace(c
->db
,c
->argv
[j
],c
->argv
[j
+1]);
217 incrRefCount(c
->argv
[j
+1]);
218 removeExpire(c
->db
,c
->argv
[j
]);
219 touchWatchedKey(c
->db
,c
->argv
[j
]);
221 server
.dirty
+= (c
->argc
-1)/2;
222 addReply(c
, nx
? shared
.cone
: shared
.ok
);
225 void msetCommand(redisClient
*c
) {
226 msetGenericCommand(c
,0);
229 void msetnxCommand(redisClient
*c
) {
230 msetGenericCommand(c
,1);
233 void incrDecrCommand(redisClient
*c
, long long incr
) {
237 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
238 if (o
!= NULL
&& checkType(c
,o
,REDIS_STRING
)) return;
239 if (getLongLongFromObjectOrReply(c
,o
,&value
,NULL
) != REDIS_OK
) return;
242 o
= createStringObjectFromLongLong(value
);
243 dbReplace(c
->db
,c
->argv
[1],o
);
244 touchWatchedKey(c
->db
,c
->argv
[1]);
246 addReply(c
,shared
.colon
);
248 addReply(c
,shared
.crlf
);
251 void incrCommand(redisClient
*c
) {
252 incrDecrCommand(c
,1);
255 void decrCommand(redisClient
*c
) {
256 incrDecrCommand(c
,-1);
259 void incrbyCommand(redisClient
*c
) {
262 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
263 incrDecrCommand(c
,incr
);
266 void decrbyCommand(redisClient
*c
) {
269 if (getLongLongFromObjectOrReply(c
, c
->argv
[2], &incr
, NULL
) != REDIS_OK
) return;
270 incrDecrCommand(c
,-incr
);
273 void appendCommand(redisClient
*c
) {
278 o
= lookupKeyWrite(c
->db
,c
->argv
[1]);
279 c
->argv
[2] = tryObjectEncoding(c
->argv
[2]);
282 retval
= dbAdd(c
->db
,c
->argv
[1],c
->argv
[2]);
283 incrRefCount(c
->argv
[2]);
284 totlen
= stringObjectLen(c
->argv
[2]);
286 if (o
->type
!= REDIS_STRING
) {
287 addReply(c
,shared
.wrongtypeerr
);
291 append
= getDecodedObject(c
->argv
[2]);
292 if (o
->encoding
== REDIS_ENCODING_RAW
&&
293 (sdslen(o
->ptr
) + sdslen(append
->ptr
)) > 512*1024*1024)
295 addReplyError(c
,"string exceeds maximum allowed size (512MB)");
296 decrRefCount(append
);
300 /* If the object is shared or encoded, we have to make a copy */
301 if (o
->refcount
!= 1 || o
->encoding
!= REDIS_ENCODING_RAW
) {
302 robj
*decoded
= getDecodedObject(o
);
303 o
= createStringObject(decoded
->ptr
, sdslen(decoded
->ptr
));
304 decrRefCount(decoded
);
305 dbReplace(c
->db
,c
->argv
[1],o
);
308 /* Append the value */
309 o
->ptr
= sdscatlen(o
->ptr
,append
->ptr
,sdslen(append
->ptr
));
310 decrRefCount(append
);
311 totlen
= sdslen(o
->ptr
);
313 touchWatchedKey(c
->db
,c
->argv
[1]);
315 addReplyLongLong(c
,totlen
);
318 void substrCommand(redisClient
*c
) {
320 long start
= atoi(c
->argv
[2]->ptr
);
321 long end
= atoi(c
->argv
[3]->ptr
);
322 size_t rangelen
, strlen
;
325 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.nullbulk
)) == NULL
||
326 checkType(c
,o
,REDIS_STRING
)) return;
328 o
= getDecodedObject(o
);
329 strlen
= sdslen(o
->ptr
);
331 /* convert negative indexes */
332 if (start
< 0) start
= strlen
+start
;
333 if (end
< 0) end
= strlen
+end
;
334 if (start
< 0) start
= 0;
335 if (end
< 0) end
= 0;
337 /* indexes sanity checks */
338 if (start
> end
|| (size_t)start
>= strlen
) {
339 /* Out of range start or start > end result in null reply */
340 addReply(c
,shared
.nullbulk
);
344 if ((size_t)end
>= strlen
) end
= strlen
-1;
345 rangelen
= (end
-start
)+1;
347 /* Return the result */
348 addReplySds(c
,sdscatprintf(sdsempty(),"$%zu\r\n",rangelen
));
349 range
= sdsnewlen((char*)o
->ptr
+start
,rangelen
);
350 addReplySds(c
,range
);
351 addReply(c
,shared
.crlf
);
355 void strlenCommand(redisClient
*c
) {
358 if ((o
= lookupKeyReadOrReply(c
,c
->argv
[1],shared
.czero
)) == NULL
||
359 checkType(c
,o
,REDIS_STRING
)) return;
361 if (o
->encoding
== REDIS_ENCODING_RAW
) {
362 addReplyLongLong(c
,sdslen(o
->ptr
));
363 } else if (o
->encoding
== REDIS_ENCODING_INT
) {
365 int len
= ll2string(llbuf
,sizeof(llbuf
),(long)o
->ptr
);
366 addReplyLongLong(c
,len
);
368 redisPanic("Unknown string encoding");